Merge lp:~kyrofa/crackly/vendor_dependencies into lp:crackly
- vendor_dependencies
- Merge into trunk
Proposed by
Kyle Fazzari
Status: | Superseded |
---|---|
Proposed branch: | lp:~kyrofa/crackly/vendor_dependencies |
Merge into: | lp:crackly |
Diff against target: |
47909 lines (+46845/-0) 205 files modified
internal/github.com/blakesmith/ar/README.md (+7/-0) internal/github.com/blakesmith/ar/common.go (+27/-0) internal/github.com/blakesmith/ar/reader.go (+134/-0) internal/github.com/blakesmith/ar/reader_test.go (+92/-0) internal/github.com/blakesmith/ar/writer.go (+103/-0) internal/github.com/blakesmith/ar/writer_test.go (+71/-0) internal/github.com/cheggaaa/pb/LICENSE (+12/-0) internal/github.com/cheggaaa/pb/README.md (+98/-0) internal/github.com/cheggaaa/pb/format.go (+42/-0) internal/github.com/cheggaaa/pb/format_test.go (+37/-0) internal/github.com/cheggaaa/pb/pb.go (+341/-0) internal/github.com/cheggaaa/pb/pb_nix.go (+7/-0) internal/github.com/cheggaaa/pb/pb_solaris.go (+5/-0) internal/github.com/cheggaaa/pb/pb_test.go (+30/-0) internal/github.com/cheggaaa/pb/pb_win.go (+16/-0) internal/github.com/cheggaaa/pb/pb_x.go (+46/-0) internal/github.com/cheggaaa/pb/reader.go (+17/-0) internal/github.com/gosexy/gettext/LICENSE (+20/-0) internal/github.com/gosexy/gettext/README.md (+94/-0) internal/github.com/gosexy/gettext/gettext.go (+207/-0) internal/github.com/gosexy/gettext/gettext_test.go (+130/-0) internal/github.com/mvo5/goconfigparser/COPYING (+19/-0) internal/github.com/mvo5/goconfigparser/README.md (+18/-0) internal/github.com/mvo5/goconfigparser/configparser.go (+181/-0) internal/github.com/mvo5/goconfigparser/configparser_test.go (+127/-0) internal/github.com/mvo5/uboot-go/uenv/env.go (+235/-0) internal/github.com/mvo5/uboot-go/uenv/env_test.go (+203/-0) internal/github.com/olekukonko/ts/LICENCE (+19/-0) internal/github.com/olekukonko/ts/README.md (+28/-0) internal/github.com/olekukonko/ts/doc.go (+36/-0) internal/github.com/olekukonko/ts/ts.go (+36/-0) internal/github.com/olekukonko/ts/ts_darwin.go (+14/-0) internal/github.com/olekukonko/ts/ts_linux.go (+13/-0) internal/github.com/olekukonko/ts/ts_other.go (+14/-0) internal/github.com/olekukonko/ts/ts_test.go (+32/-0) internal/github.com/olekukonko/ts/ts_unix.go (+14/-0) internal/github.com/olekukonko/ts/ts_windows.go (+64/-0) internal/github.com/olekukonko/ts/ts_x.go (+46/-0) internal/gopkg.in/check.v1/LICENSE (+25/-0) internal/gopkg.in/check.v1/README.md (+20/-0) internal/gopkg.in/check.v1/TODO (+2/-0) internal/gopkg.in/check.v1/benchmark.go (+163/-0) internal/gopkg.in/check.v1/benchmark_test.go (+91/-0) internal/gopkg.in/check.v1/bootstrap_test.go (+82/-0) internal/gopkg.in/check.v1/check.go (+945/-0) internal/gopkg.in/check.v1/check_test.go (+207/-0) internal/gopkg.in/check.v1/checkers.go (+458/-0) internal/gopkg.in/check.v1/checkers_test.go (+272/-0) internal/gopkg.in/check.v1/export_test.go (+9/-0) internal/gopkg.in/check.v1/fixture_test.go (+484/-0) internal/gopkg.in/check.v1/foundation_test.go (+335/-0) internal/gopkg.in/check.v1/helpers.go (+231/-0) internal/gopkg.in/check.v1/helpers_test.go (+519/-0) internal/gopkg.in/check.v1/printer.go (+168/-0) internal/gopkg.in/check.v1/printer_test.go (+109/-0) internal/gopkg.in/check.v1/run.go (+175/-0) internal/gopkg.in/check.v1/run_test.go (+419/-0) internal/gopkg.in/yaml.v2/LICENSE (+188/-0) internal/gopkg.in/yaml.v2/LICENSE.libyaml (+31/-0) internal/gopkg.in/yaml.v2/README.md (+128/-0) internal/gopkg.in/yaml.v2/apic.go (+742/-0) internal/gopkg.in/yaml.v2/decode.go (+683/-0) internal/gopkg.in/yaml.v2/decode_test.go (+966/-0) internal/gopkg.in/yaml.v2/emitterc.go (+1685/-0) internal/gopkg.in/yaml.v2/encode.go (+306/-0) internal/gopkg.in/yaml.v2/encode_test.go (+501/-0) internal/gopkg.in/yaml.v2/parserc.go (+1096/-0) internal/gopkg.in/yaml.v2/readerc.go (+391/-0) internal/gopkg.in/yaml.v2/resolve.go (+203/-0) internal/gopkg.in/yaml.v2/scannerc.go (+2710/-0) internal/gopkg.in/yaml.v2/sorter.go (+104/-0) internal/gopkg.in/yaml.v2/suite_test.go (+12/-0) internal/gopkg.in/yaml.v2/writerc.go (+89/-0) internal/gopkg.in/yaml.v2/yaml.go (+346/-0) internal/gopkg.in/yaml.v2/yamlh.go (+716/-0) internal/gopkg.in/yaml.v2/yamlprivateh.go (+173/-0) internal/launchpad.net/gocheck/LICENSE (+25/-0) internal/launchpad.net/gocheck/Makefile (+30/-0) internal/launchpad.net/gocheck/TODO (+2/-0) internal/launchpad.net/gocheck/benchmark.go (+136/-0) internal/launchpad.net/gocheck/benchmark_test.go (+75/-0) internal/launchpad.net/gocheck/bootstrap_test.go (+82/-0) internal/launchpad.net/gocheck/checkers.go (+458/-0) internal/launchpad.net/gocheck/checkers_test.go (+272/-0) internal/launchpad.net/gocheck/export_test.go (+9/-0) internal/launchpad.net/gocheck/fixture_test.go (+479/-0) internal/launchpad.net/gocheck/foundation_test.go (+335/-0) internal/launchpad.net/gocheck/gocheck.go (+917/-0) internal/launchpad.net/gocheck/gocheck_test.go (+196/-0) internal/launchpad.net/gocheck/helpers.go (+224/-0) internal/launchpad.net/gocheck/helpers_test.go (+491/-0) internal/launchpad.net/gocheck/printer.go (+168/-0) internal/launchpad.net/gocheck/printer_test.go (+109/-0) internal/launchpad.net/gocheck/run.go (+152/-0) internal/launchpad.net/gocheck/run_test.go (+397/-0) internal/launchpad.net/snappy/clickdeb/deb.go (+504/-0) internal/launchpad.net/snappy/clickdeb/deb_test.go (+241/-0) internal/launchpad.net/snappy/clickdeb/verify.go (+97/-0) internal/launchpad.net/snappy/clickdeb/verify_test.go (+87/-0) internal/launchpad.net/snappy/coreconfig/config.go (+262/-0) internal/launchpad.net/snappy/coreconfig/config_test.go (+400/-0) internal/launchpad.net/snappy/helpers/cmp.go (+118/-0) internal/launchpad.net/snappy/helpers/cmp_test.go (+148/-0) internal/launchpad.net/snappy/helpers/cp.go (+136/-0) internal/launchpad.net/snappy/helpers/cp_linux.go (+48/-0) internal/launchpad.net/snappy/helpers/cp_linux_test.go (+46/-0) internal/launchpad.net/snappy/helpers/cp_other.go (+31/-0) internal/launchpad.net/snappy/helpers/cp_test.go (+214/-0) internal/launchpad.net/snappy/helpers/helpers.go (+525/-0) internal/launchpad.net/snappy/helpers/helpers_test.go (+485/-0) internal/launchpad.net/snappy/helpers/touch.go (+61/-0) internal/launchpad.net/snappy/helpers/touch_test.go (+76/-0) internal/launchpad.net/snappy/helpers/winsize.go (+48/-0) internal/launchpad.net/snappy/i18n/i18n.go (+45/-0) internal/launchpad.net/snappy/i18n/i18n_test.go (+111/-0) internal/launchpad.net/snappy/logger/logger.go (+151/-0) internal/launchpad.net/snappy/logger/logger_test.go (+134/-0) internal/launchpad.net/snappy/oauth/oauth.go (+80/-0) internal/launchpad.net/snappy/oauth/oauth_test.go (+69/-0) internal/launchpad.net/snappy/partition/assets.go (+87/-0) internal/launchpad.net/snappy/partition/assets_test.go (+36/-0) internal/launchpad.net/snappy/partition/bootloader.go (+300/-0) internal/launchpad.net/snappy/partition/bootloader_grub.go (+133/-0) internal/launchpad.net/snappy/partition/bootloader_grub_test.go (+182/-0) internal/launchpad.net/snappy/partition/bootloader_uboot.go (+268/-0) internal/launchpad.net/snappy/partition/bootloader_uboot_test.go (+384/-0) internal/launchpad.net/snappy/partition/dirs.go (+41/-0) internal/launchpad.net/snappy/partition/mount.go (+153/-0) internal/launchpad.net/snappy/partition/mount_test.go (+64/-0) internal/launchpad.net/snappy/partition/partition.go (+622/-0) internal/launchpad.net/snappy/partition/partition_test.go (+450/-0) internal/launchpad.net/snappy/partition/utils.go (+82/-0) internal/launchpad.net/snappy/partition/utils_test.go (+47/-0) internal/launchpad.net/snappy/pkg/types.go (+60/-0) internal/launchpad.net/snappy/pkg/types_test.go (+66/-0) internal/launchpad.net/snappy/policy/policy.go (+144/-0) internal/launchpad.net/snappy/policy/policy_test.go (+186/-0) internal/launchpad.net/snappy/progress/isatty.go (+31/-0) internal/launchpad.net/snappy/progress/progress.go (+204/-0) internal/launchpad.net/snappy/progress/progress_test.go (+150/-0) internal/launchpad.net/snappy/provisioning/provisioning.go (+150/-0) internal/launchpad.net/snappy/provisioning/provisioning_test.go (+183/-0) internal/launchpad.net/snappy/release/release.go (+99/-0) internal/launchpad.net/snappy/release/release_test.go (+97/-0) internal/launchpad.net/snappy/snappy/arch.go (+48/-0) internal/launchpad.net/snappy/snappy/auth.go (+160/-0) internal/launchpad.net/snappy/snappy/auth_test.go (+148/-0) internal/launchpad.net/snappy/snappy/build.go (+574/-0) internal/launchpad.net/snappy/snappy/build_test.go (+495/-0) internal/launchpad.net/snappy/snappy/click.go (+812/-0) internal/launchpad.net/snappy/snappy/click_test.go (+1564/-0) internal/launchpad.net/snappy/snappy/common_test.go (+238/-0) internal/launchpad.net/snappy/snappy/config.go (+71/-0) internal/launchpad.net/snappy/snappy/config_test.go (+129/-0) internal/launchpad.net/snappy/snappy/datadir.go (+106/-0) internal/launchpad.net/snappy/snappy/datadir_test.go (+121/-0) internal/launchpad.net/snappy/snappy/dbus.go (+84/-0) internal/launchpad.net/snappy/snappy/dbus_test.go (+95/-0) internal/launchpad.net/snappy/snappy/dirs.go (+74/-0) internal/launchpad.net/snappy/snappy/errors.go (+275/-0) internal/launchpad.net/snappy/snappy/firstboot.go (+152/-0) internal/launchpad.net/snappy/snappy/firstboot_test.go (+190/-0) internal/launchpad.net/snappy/snappy/globals.go (+40/-0) internal/launchpad.net/snappy/snappy/hashes.go (+121/-0) internal/launchpad.net/snappy/snappy/hashes_test.go (+154/-0) internal/launchpad.net/snappy/snappy/hwaccess.go (+248/-0) internal/launchpad.net/snappy/snappy/hwaccess_test.go (+300/-0) internal/launchpad.net/snappy/snappy/install.go (+185/-0) internal/launchpad.net/snappy/snappy/install_test.go (+265/-0) internal/launchpad.net/snappy/snappy/list.go (+34/-0) internal/launchpad.net/snappy/snappy/oem.go (+293/-0) internal/launchpad.net/snappy/snappy/oem_test.go (+93/-0) internal/launchpad.net/snappy/snappy/parts.go (+335/-0) internal/launchpad.net/snappy/snappy/parts_test.go (+180/-0) internal/launchpad.net/snappy/snappy/purge.go (+93/-0) internal/launchpad.net/snappy/snappy/purge_test.go (+200/-0) internal/launchpad.net/snappy/snappy/remove.go (+72/-0) internal/launchpad.net/snappy/snappy/remove_test.go (+87/-0) internal/launchpad.net/snappy/snappy/rollback.go (+56/-0) internal/launchpad.net/snappy/snappy/rollback_test.go (+63/-0) internal/launchpad.net/snappy/snappy/search.go (+29/-0) internal/launchpad.net/snappy/snappy/security.go (+226/-0) internal/launchpad.net/snappy/snappy/security_test.go (+302/-0) internal/launchpad.net/snappy/snappy/service.go (+180/-0) internal/launchpad.net/snappy/snappy/service_test.go (+160/-0) internal/launchpad.net/snappy/snappy/set.go (+57/-0) internal/launchpad.net/snappy/snappy/set_test.go (+99/-0) internal/launchpad.net/snappy/snappy/snapp.go (+1911/-0) internal/launchpad.net/snappy/snappy/snapp_test.go (+1615/-0) internal/launchpad.net/snappy/snappy/sort.go (+206/-0) internal/launchpad.net/snappy/snappy/sort_test.go (+103/-0) internal/launchpad.net/snappy/snappy/systemimage.go (+518/-0) internal/launchpad.net/snappy/snappy/systemimage_native.go (+211/-0) internal/launchpad.net/snappy/snappy/systemimage_native_test.go (+123/-0) internal/launchpad.net/snappy/snappy/systemimage_test.go (+486/-0) internal/launchpad.net/snappy/snappy/timeout.go (+63/-0) internal/launchpad.net/snappy/snappy/timeout_test.go (+49/-0) internal/launchpad.net/snappy/systemd/systemd.go (+315/-0) internal/launchpad.net/snappy/systemd/systemd_test.go (+314/-0) internal/vendor.json (+166/-0) main.go (+43/-0) operations/generate_desktop_files.go (+104/-0) operations/install.go (+51/-0) operations/remove.go (+26/-0) snap/metadata.go (+21/-0) |
To merge this branch: | bzr merge lp:~kyrofa/crackly/vendor_dependencies |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Unity API Team | Pending | ||
Review via email: mp+276268@code.launchpad.net |
This proposal has been superseded by a proposal from 2015-10-30.
Commit message
Vendor all dependencies.
Description of the change
Vendor all dependencies.
To post a comment you must log in.
Unmerged revisions
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added directory 'internal' |
2 | === added directory 'internal/github.com' |
3 | === added directory 'internal/github.com/blakesmith' |
4 | === added directory 'internal/github.com/blakesmith/ar' |
5 | === added file 'internal/github.com/blakesmith/ar/README.md' |
6 | --- internal/github.com/blakesmith/ar/README.md 1970-01-01 00:00:00 +0000 |
7 | +++ internal/github.com/blakesmith/ar/README.md 2015-10-30 14:12:15 +0000 |
8 | @@ -0,0 +1,7 @@ |
9 | +# Golang ar (archive) file reader |
10 | + |
11 | +This is a simple library for reading and writing [ar](http://en.wikipedia.org/wiki/Ar_(Unix)) files in common format. It is influenced heavily in style and interface from the golang [tar](http://golang.org/pkg/archive/tar/) package. |
12 | + |
13 | +## Author |
14 | + |
15 | +Written by Blake Smith <blakesmith0@gmail.com> |
16 | |
17 | === added file 'internal/github.com/blakesmith/ar/common.go' |
18 | --- internal/github.com/blakesmith/ar/common.go 1970-01-01 00:00:00 +0000 |
19 | +++ internal/github.com/blakesmith/ar/common.go 2015-10-30 14:12:15 +0000 |
20 | @@ -0,0 +1,27 @@ |
21 | +package ar |
22 | + |
23 | +import ( |
24 | + "time" |
25 | +) |
26 | + |
27 | +const ( |
28 | + HEADER_BYTE_SIZE = 60 |
29 | + GLOBAL_HEADER = "!<arch>\n" |
30 | +) |
31 | + |
32 | +type Header struct { |
33 | + Name string |
34 | + ModTime time.Time |
35 | + Uid int |
36 | + Gid int |
37 | + Mode int64 |
38 | + Size int64 |
39 | +} |
40 | + |
41 | +type slicer []byte |
42 | + |
43 | +func (sp *slicer) next(n int) (b []byte) { |
44 | + s := *sp |
45 | + b, *sp = s[0:n], s[n:] |
46 | + return |
47 | +} |
48 | |
49 | === added file 'internal/github.com/blakesmith/ar/reader.go' |
50 | --- internal/github.com/blakesmith/ar/reader.go 1970-01-01 00:00:00 +0000 |
51 | +++ internal/github.com/blakesmith/ar/reader.go 2015-10-30 14:12:15 +0000 |
52 | @@ -0,0 +1,134 @@ |
53 | +package ar |
54 | + |
55 | +import ( |
56 | + "io" |
57 | + "io/ioutil" |
58 | + "os" |
59 | + "strconv" |
60 | + "time" |
61 | +) |
62 | + |
63 | +// Provides read access to an ar archive. |
64 | +// Call next to skip files |
65 | +// |
66 | +// Example: |
67 | +// reader := NewReader(f) |
68 | +// var buf bytes.Buffer |
69 | +// for { |
70 | +// _, err := reader.Next() |
71 | +// if err == io.EOF { |
72 | +// break |
73 | +// } |
74 | +// if err != nil { |
75 | +// t.Errorf(err.Error()) |
76 | +// } |
77 | +// io.Copy(&buf, reader) |
78 | +// } |
79 | + |
80 | +type Reader struct { |
81 | + r io.Reader |
82 | + nb int64 |
83 | + pad int64 |
84 | +} |
85 | + |
86 | +// Copies read data to r. Strips the global ar header. |
87 | +func NewReader(r io.Reader) *Reader { |
88 | + io.CopyN(ioutil.Discard, r, 8) // Discard global header |
89 | + |
90 | + return &Reader{r: r} |
91 | +} |
92 | + |
93 | +func (rd *Reader) string(b []byte) string { |
94 | + i := len(b) - 1 |
95 | + for i > 0 && b[i] == 32 { |
96 | + i-- |
97 | + } |
98 | + |
99 | + return string(b[0 : i+1]) |
100 | +} |
101 | + |
102 | +func (rd *Reader) numeric(b []byte) int64 { |
103 | + i := len(b) - 1 |
104 | + for i > 0 && b[i] == 32 { |
105 | + i-- |
106 | + } |
107 | + |
108 | + n, _ := strconv.ParseInt(string(b[0:i+1]), 10, 64) |
109 | + |
110 | + return n |
111 | +} |
112 | + |
113 | +func (rd *Reader) octal(b []byte) int64 { |
114 | + i := len(b) - 1 |
115 | + for i > 0 && b[i] == 32 { |
116 | + i-- |
117 | + } |
118 | + |
119 | + n, _ := strconv.ParseInt(string(b[3:i+1]), 8, 64) |
120 | + |
121 | + return n |
122 | +} |
123 | + |
124 | +func (rd *Reader) skipUnread() error { |
125 | + skip := rd.nb + rd.pad |
126 | + rd.nb, rd.pad = 0, 0 |
127 | + if seeker, ok := rd.r.(io.Seeker); ok { |
128 | + _, err := seeker.Seek(skip, os.SEEK_CUR) |
129 | + return err |
130 | + } |
131 | + |
132 | + _, err := io.CopyN(ioutil.Discard, rd.r, skip) |
133 | + return err |
134 | +} |
135 | + |
136 | +func (rd *Reader) readHeader() (*Header, error) { |
137 | + headerBuf := make([]byte, HEADER_BYTE_SIZE) |
138 | + if _, err := io.ReadFull(rd.r, headerBuf); err != nil { |
139 | + return nil, err |
140 | + } |
141 | + |
142 | + header := new(Header) |
143 | + s := slicer(headerBuf) |
144 | + |
145 | + header.Name = rd.string(s.next(16)) |
146 | + header.ModTime = time.Unix(rd.numeric(s.next(12)), 0) |
147 | + header.Uid = int(rd.numeric(s.next(6))) |
148 | + header.Gid = int(rd.numeric(s.next(6))) |
149 | + header.Mode = rd.octal(s.next(8)) |
150 | + header.Size = rd.numeric(s.next(10)) |
151 | + |
152 | + rd.nb = int64(header.Size) |
153 | + if header.Size%2 == 1 { |
154 | + rd.pad = 1 |
155 | + } else { |
156 | + rd.pad = 0 |
157 | + } |
158 | + |
159 | + return header, nil |
160 | +} |
161 | + |
162 | +// Call Next() to skip to the next file in the archive file. |
163 | +// Returns a Header which contains the metadata about the |
164 | +// file in the archive. |
165 | +func (rd *Reader) Next() (*Header, error) { |
166 | + err := rd.skipUnread() |
167 | + if err != nil { |
168 | + return nil, err |
169 | + } |
170 | + |
171 | + return rd.readHeader() |
172 | +} |
173 | + |
174 | +// Read data from the current entry in the archive. |
175 | +func (rd *Reader) Read(b []byte) (n int, err error) { |
176 | + if rd.nb == 0 { |
177 | + return 0, io.EOF |
178 | + } |
179 | + if int64(len(b)) > rd.nb { |
180 | + b = b[0:rd.nb] |
181 | + } |
182 | + n, err = rd.r.Read(b) |
183 | + rd.nb -= int64(n) |
184 | + |
185 | + return |
186 | +} |
187 | |
188 | === added file 'internal/github.com/blakesmith/ar/reader_test.go' |
189 | --- internal/github.com/blakesmith/ar/reader_test.go 1970-01-01 00:00:00 +0000 |
190 | +++ internal/github.com/blakesmith/ar/reader_test.go 2015-10-30 14:12:15 +0000 |
191 | @@ -0,0 +1,92 @@ |
192 | +package ar |
193 | + |
194 | +import ( |
195 | + "bytes" |
196 | + "io" |
197 | + "os" |
198 | + "testing" |
199 | + "time" |
200 | +) |
201 | + |
202 | +func TestReadHeader(t *testing.T) { |
203 | + f, err := os.Open("./fixtures/hello.a") |
204 | + defer f.Close() |
205 | + |
206 | + if err != nil { |
207 | + t.Errorf(err.Error()) |
208 | + } |
209 | + reader := NewReader(f) |
210 | + header, err := reader.Next() |
211 | + if err != nil { |
212 | + t.Errorf(err.Error()) |
213 | + } |
214 | + |
215 | + expectedName := "hello.txt" |
216 | + if header.Name != expectedName { |
217 | + t.Errorf("Header name should be %s but is %s", expectedName, header.Name) |
218 | + } |
219 | + expectedModTime := time.Unix(1361157466, 0) |
220 | + if header.ModTime != expectedModTime { |
221 | + t.Errorf("ModTime should be %s but is %s", expectedModTime, header.ModTime) |
222 | + } |
223 | + expectedUid := 501 |
224 | + if header.Uid != expectedUid { |
225 | + t.Errorf("Uid should be %s but is %s", expectedUid, header.Uid) |
226 | + } |
227 | + expectedGid := 20 |
228 | + if header.Gid != expectedGid { |
229 | + t.Errorf("Gid should be %s but is %s", expectedGid, header.Gid) |
230 | + } |
231 | + expectedMode := int64(0644) |
232 | + if header.Mode != expectedMode { |
233 | + t.Errorf("Mode should be %s but is %s", expectedMode, header.Mode) |
234 | + } |
235 | +} |
236 | + |
237 | +func TestReadBody(t *testing.T) { |
238 | + f, err := os.Open("./fixtures/hello.a") |
239 | + defer f.Close() |
240 | + |
241 | + if err != nil { |
242 | + t.Errorf(err.Error()) |
243 | + } |
244 | + reader := NewReader(f) |
245 | + _, err = reader.Next() |
246 | + if err != nil && err != io.EOF { |
247 | + t.Errorf(err.Error()) |
248 | + } |
249 | + var buf bytes.Buffer |
250 | + io.Copy(&buf, reader) |
251 | + |
252 | + expected := []byte("Hello world!\n") |
253 | + actual := buf.Bytes() |
254 | + if !bytes.Equal(actual, expected) { |
255 | + t.Errorf("Data value should be %s but is %s", expected, actual) |
256 | + } |
257 | +} |
258 | + |
259 | +func TestReadMulti(t *testing.T) { |
260 | + f, err := os.Open("./fixtures/multi_archive.a") |
261 | + defer f.Close() |
262 | + |
263 | + if err != nil { |
264 | + t.Errorf(err.Error()) |
265 | + } |
266 | + reader := NewReader(f) |
267 | + var buf bytes.Buffer |
268 | + for { |
269 | + _, err := reader.Next() |
270 | + if err == io.EOF { |
271 | + break |
272 | + } |
273 | + if err != nil { |
274 | + t.Errorf(err.Error()) |
275 | + } |
276 | + io.Copy(&buf, reader) |
277 | + } |
278 | + expected := []byte("Hello world!\nI love lamp.\n") |
279 | + actual := buf.Bytes() |
280 | + if !bytes.Equal(expected, actual) { |
281 | + t.Errorf("Concatted byte buffer should be %s but is %s", expected, actual) |
282 | + } |
283 | +} |
284 | |
285 | === added file 'internal/github.com/blakesmith/ar/writer.go' |
286 | --- internal/github.com/blakesmith/ar/writer.go 1970-01-01 00:00:00 +0000 |
287 | +++ internal/github.com/blakesmith/ar/writer.go 2015-10-30 14:12:15 +0000 |
288 | @@ -0,0 +1,103 @@ |
289 | +package ar |
290 | + |
291 | +import ( |
292 | + "errors" |
293 | + "io" |
294 | + "strconv" |
295 | +) |
296 | + |
297 | +var ( |
298 | + ErrWriteTooLong = errors.New("ar: write too long") |
299 | +) |
300 | + |
301 | +// Writer provides sequential writing of an ar archive. |
302 | +// An ar archive is sequence of header file pairs |
303 | +// Call WriteHeader to begin writing a new file, then call Write to supply the file's data |
304 | +// |
305 | +// Example: |
306 | +// archive := ar.NewWriter(writer) |
307 | +// archive.WriteGlobalHeader() |
308 | +// header := new(ar.Header) |
309 | +// header.Size = 15 // bytes |
310 | +// if err := archive.WriteHeader(header); err != nil { |
311 | +// return err |
312 | +// } |
313 | +// io.Copy(archive, data) |
314 | +type Writer struct { |
315 | + w io.Writer |
316 | + nb int64 // number of unwritten bytes for the current file entry |
317 | +} |
318 | + |
319 | +// Create a new ar writer that writes to w |
320 | +func NewWriter(w io.Writer) *Writer { return &Writer{w: w} } |
321 | + |
322 | +func (aw *Writer) numeric(b []byte, x int64) { |
323 | + s := strconv.FormatInt(x, 10) |
324 | + for len(s) < len(b) { |
325 | + s = s + " " |
326 | + } |
327 | + copy(b, []byte(s)) |
328 | +} |
329 | + |
330 | +func (aw *Writer) octal(b []byte, x int64) { |
331 | + s := "100" + strconv.FormatInt(x, 8) |
332 | + for len(s) < len(b) { |
333 | + s = s + " " |
334 | + } |
335 | + copy(b, []byte(s)) |
336 | +} |
337 | + |
338 | +func (aw *Writer) string(b []byte, str string) { |
339 | + s := str |
340 | + for len(s) < len(b) { |
341 | + s = s + " " |
342 | + } |
343 | + copy(b, []byte(s)) |
344 | +} |
345 | + |
346 | +// Writes to the current entry in the ar archive |
347 | +// Returns ErrWriteTooLong if more than header.Size |
348 | +// bytes are written after a call to WriteHeader |
349 | +func (aw *Writer) Write(b []byte) (n int, err error) { |
350 | + if int64(len(b)) > aw.nb { |
351 | + b = b[0:aw.nb] |
352 | + err = ErrWriteTooLong |
353 | + } |
354 | + n, werr := aw.w.Write(b) |
355 | + aw.nb -= int64(n) |
356 | + if werr != nil { |
357 | + return n, werr |
358 | + } |
359 | + |
360 | + if len(b)%2 == 1 { // data size must be aligned to an even byte |
361 | + n2, _ := aw.w.Write([]byte{'\n'}) |
362 | + return n + n2, err |
363 | + } |
364 | + |
365 | + return |
366 | +} |
367 | + |
368 | +func (aw *Writer) WriteGlobalHeader() error { |
369 | + _, err := aw.w.Write([]byte(GLOBAL_HEADER)) |
370 | + return err |
371 | +} |
372 | + |
373 | +// Writes the header to the underlying writer and prepares |
374 | +// to receive the file payload |
375 | +func (aw *Writer) WriteHeader(hdr *Header) error { |
376 | + aw.nb = int64(hdr.Size) |
377 | + header := make([]byte, HEADER_BYTE_SIZE) |
378 | + s := slicer(header) |
379 | + |
380 | + aw.string(s.next(16), hdr.Name) |
381 | + aw.numeric(s.next(12), hdr.ModTime.Unix()) |
382 | + aw.numeric(s.next(6), int64(hdr.Uid)) |
383 | + aw.numeric(s.next(6), int64(hdr.Gid)) |
384 | + aw.octal(s.next(8), hdr.Mode) |
385 | + aw.numeric(s.next(10), hdr.Size) |
386 | + aw.string(s.next(2), "`\n") |
387 | + |
388 | + _, err := aw.w.Write(header) |
389 | + |
390 | + return err |
391 | +} |
392 | |
393 | === added file 'internal/github.com/blakesmith/ar/writer_test.go' |
394 | --- internal/github.com/blakesmith/ar/writer_test.go 1970-01-01 00:00:00 +0000 |
395 | +++ internal/github.com/blakesmith/ar/writer_test.go 2015-10-30 14:12:15 +0000 |
396 | @@ -0,0 +1,71 @@ |
397 | +package ar |
398 | + |
399 | +import ( |
400 | + "bytes" |
401 | + "io/ioutil" |
402 | + "os" |
403 | + "testing" |
404 | + "time" |
405 | +) |
406 | + |
407 | +func TestGlobalHeaderWrite(t *testing.T) { |
408 | + var buf bytes.Buffer |
409 | + writer := NewWriter(&buf) |
410 | + if err := writer.WriteGlobalHeader(); err != nil { |
411 | + t.Errorf(err.Error()) |
412 | + } |
413 | + |
414 | + globalHeader := buf.Bytes() |
415 | + expectedHeader := []byte("!<arch>\n") |
416 | + if !bytes.Equal(globalHeader, expectedHeader) { |
417 | + t.Errorf("Global header should be %s but is %s", expectedHeader, globalHeader) |
418 | + } |
419 | +} |
420 | + |
421 | +func TestSimpleFile(t *testing.T) { |
422 | + hdr := new(Header) |
423 | + body := "Hello world!\n" |
424 | + hdr.ModTime = time.Unix(1361157466, 0) |
425 | + hdr.Name = "hello.txt" |
426 | + hdr.Size = int64(len(body)) |
427 | + hdr.Mode = 0644 |
428 | + hdr.Uid = 501 |
429 | + hdr.Gid = 20 |
430 | + |
431 | + var buf bytes.Buffer |
432 | + writer := NewWriter(&buf) |
433 | + writer.WriteGlobalHeader() |
434 | + writer.WriteHeader(hdr) |
435 | + _, err := writer.Write([]byte(body)) |
436 | + if err != nil { |
437 | + t.Errorf(err.Error()) |
438 | + } |
439 | + |
440 | + f, _ := os.Open("./fixtures/hello.a") |
441 | + defer f.Close() |
442 | + |
443 | + b, err := ioutil.ReadAll(f) |
444 | + if err != nil { |
445 | + t.Errorf(err.Error()) |
446 | + } |
447 | + |
448 | + actual := buf.Bytes() |
449 | + if !bytes.Equal(b, actual) { |
450 | + t.Errorf("Expected %s to equal %s", actual, b) |
451 | + } |
452 | +} |
453 | + |
454 | +func TestWriteTooLong(t *testing.T) { |
455 | + body := "Hello world!\n" |
456 | + |
457 | + hdr := new(Header) |
458 | + hdr.Size = 1 |
459 | + |
460 | + var buf bytes.Buffer |
461 | + writer := NewWriter(&buf) |
462 | + writer.WriteHeader(hdr) |
463 | + _, err := writer.Write([]byte(body)) |
464 | + if err != ErrWriteTooLong { |
465 | + t.Errorf("Error should have been: %s", ErrWriteTooLong) |
466 | + } |
467 | +} |
468 | |
469 | === added directory 'internal/github.com/cheggaaa' |
470 | === added directory 'internal/github.com/cheggaaa/pb' |
471 | === added file 'internal/github.com/cheggaaa/pb/LICENSE' |
472 | --- internal/github.com/cheggaaa/pb/LICENSE 1970-01-01 00:00:00 +0000 |
473 | +++ internal/github.com/cheggaaa/pb/LICENSE 2015-10-30 14:12:15 +0000 |
474 | @@ -0,0 +1,12 @@ |
475 | +Copyright (c) 2012, Sergey Cherepanov |
476 | +All rights reserved. |
477 | + |
478 | +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: |
479 | + |
480 | +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. |
481 | + |
482 | +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. |
483 | + |
484 | +* Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. |
485 | + |
486 | +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
487 | \ No newline at end of file |
488 | |
489 | === added file 'internal/github.com/cheggaaa/pb/README.md' |
490 | --- internal/github.com/cheggaaa/pb/README.md 1970-01-01 00:00:00 +0000 |
491 | +++ internal/github.com/cheggaaa/pb/README.md 2015-10-30 14:12:15 +0000 |
492 | @@ -0,0 +1,98 @@ |
493 | +## Terminal progress bar for Go |
494 | + |
495 | +Simple progress bar for console programms. |
496 | + |
497 | + |
498 | +### Installation |
499 | +``` |
500 | +go get github.com/cheggaaa/pb |
501 | +``` |
502 | + |
503 | +### Usage |
504 | +```Go |
505 | +package main |
506 | + |
507 | +import ( |
508 | + "github.com/cheggaaa/pb" |
509 | + "time" |
510 | +) |
511 | + |
512 | +func main() { |
513 | + count := 100000 |
514 | + bar := pb.StartNew(count) |
515 | + for i := 0; i < count; i++ { |
516 | + bar.Increment() |
517 | + time.Sleep(time.Millisecond) |
518 | + } |
519 | + bar.FinishPrint("The End!") |
520 | +} |
521 | +``` |
522 | +Result will be like this: |
523 | +``` |
524 | +> go run test.go |
525 | +37158 / 100000 [================>_______________________________] 37.16% 1m11s |
526 | +``` |
527 | + |
528 | + |
529 | +More functions? |
530 | +```Go |
531 | +// create bar |
532 | +bar := pb.New(count) |
533 | + |
534 | +// refresh info every second (default 200ms) |
535 | +bar.SetRefreshRate(time.Second) |
536 | + |
537 | +// show percents (by default already true) |
538 | +bar.ShowPercent = true |
539 | + |
540 | +// show bar (by default already true) |
541 | +bar.ShowBar = true |
542 | + |
543 | +// no need counters |
544 | +bar.ShowCounters = false |
545 | + |
546 | +// show "time left" |
547 | +bar.ShowTimeLeft = true |
548 | + |
549 | +// show average speed |
550 | +bar.ShowSpeed = true |
551 | + |
552 | +// sets the width of the progress bar |
553 | +bar.SetWith(80) |
554 | + |
555 | +// sets the width of the progress bar, but if terminal size smaller will be ignored |
556 | +bar.SetMaxWith(80) |
557 | + |
558 | +// convert output to readable format (like KB, MB) |
559 | +bar.SetUnits(pb.U_BYTES) |
560 | + |
561 | +// and start |
562 | +bar.Start() |
563 | +``` |
564 | + |
565 | +Want handle progress of io operations? |
566 | +```Go |
567 | +// create and start bar |
568 | +bar := pb.New(myDataLen).SetUnits(pb.U_BYTES) |
569 | +bar.Start() |
570 | + |
571 | +// my io.Reader |
572 | +r := myReader |
573 | + |
574 | +// my io.Writer |
575 | +w := myWriter |
576 | + |
577 | +// create multi writer |
578 | +writer := io.MultiWriter(w, bar) |
579 | + |
580 | +// and copy |
581 | +io.Copy(writer, r) |
582 | + |
583 | +// show example/copy/copy.go for advanced example |
584 | + |
585 | +``` |
586 | + |
587 | +Not like the looks? |
588 | +```Go |
589 | +bar.Format("<.- >") |
590 | +``` |
591 | |
592 | === added file 'internal/github.com/cheggaaa/pb/format.go' |
593 | --- internal/github.com/cheggaaa/pb/format.go 1970-01-01 00:00:00 +0000 |
594 | +++ internal/github.com/cheggaaa/pb/format.go 2015-10-30 14:12:15 +0000 |
595 | @@ -0,0 +1,42 @@ |
596 | +package pb |
597 | + |
598 | +import ( |
599 | + "fmt" |
600 | + "strconv" |
601 | + "strings" |
602 | +) |
603 | + |
604 | +const ( |
605 | + // By default, without type handle |
606 | + U_NO = 0 |
607 | + // Handle as b, Kb, Mb, etc |
608 | + U_BYTES = 1 |
609 | +) |
610 | + |
611 | +// Format integer |
612 | +func Format(i int64, units int) string { |
613 | + switch units { |
614 | + case U_BYTES: |
615 | + return FormatBytes(i) |
616 | + } |
617 | + // by default just convert to string |
618 | + return strconv.Itoa(int(i)) |
619 | +} |
620 | + |
621 | +// Convert bytes to human readable string. Like a 2 MB, 64.2 KB, 52 B |
622 | +func FormatBytes(i int64) (result string) { |
623 | + switch { |
624 | + case i > (1024 * 1024 * 1024 * 1024): |
625 | + result = fmt.Sprintf("%#.02f TB", float64(i)/1024/1024/1024/1024) |
626 | + case i > (1024 * 1024 * 1024): |
627 | + result = fmt.Sprintf("%#.02f GB", float64(i)/1024/1024/1024) |
628 | + case i > (1024 * 1024): |
629 | + result = fmt.Sprintf("%#.02f MB", float64(i)/1024/1024) |
630 | + case i > 1024: |
631 | + result = fmt.Sprintf("%#.02f KB", float64(i)/1024) |
632 | + default: |
633 | + result = fmt.Sprintf("%d B", i) |
634 | + } |
635 | + result = strings.Trim(result, " ") |
636 | + return |
637 | +} |
638 | |
639 | === added file 'internal/github.com/cheggaaa/pb/format_test.go' |
640 | --- internal/github.com/cheggaaa/pb/format_test.go 1970-01-01 00:00:00 +0000 |
641 | +++ internal/github.com/cheggaaa/pb/format_test.go 2015-10-30 14:12:15 +0000 |
642 | @@ -0,0 +1,37 @@ |
643 | +package pb |
644 | + |
645 | +import ( |
646 | + "fmt" |
647 | + "strconv" |
648 | + "testing" |
649 | +) |
650 | + |
651 | +func Test_DefaultsToInteger(t *testing.T) { |
652 | + value := int64(1000) |
653 | + expected := strconv.Itoa(int(value)) |
654 | + actual := Format(value, -1) |
655 | + |
656 | + if actual != expected { |
657 | + t.Error(fmt.Sprintf("Expected {%s} was {%s}", expected, actual)) |
658 | + } |
659 | +} |
660 | + |
661 | +func Test_CanFormatAsInteger(t *testing.T) { |
662 | + value := int64(1000) |
663 | + expected := strconv.Itoa(int(value)) |
664 | + actual := Format(value, U_NO) |
665 | + |
666 | + if actual != expected { |
667 | + t.Error(fmt.Sprintf("Expected {%s} was {%s}", expected, actual)) |
668 | + } |
669 | +} |
670 | + |
671 | +func Test_CanFormatAsBytes(t *testing.T) { |
672 | + value := int64(1000) |
673 | + expected := "1000 B" |
674 | + actual := Format(value, U_BYTES) |
675 | + |
676 | + if actual != expected { |
677 | + t.Error(fmt.Sprintf("Expected {%s} was {%s}", expected, actual)) |
678 | + } |
679 | +} |
680 | |
681 | === added file 'internal/github.com/cheggaaa/pb/pb.go' |
682 | --- internal/github.com/cheggaaa/pb/pb.go 1970-01-01 00:00:00 +0000 |
683 | +++ internal/github.com/cheggaaa/pb/pb.go 2015-10-30 14:12:15 +0000 |
684 | @@ -0,0 +1,341 @@ |
685 | +package pb |
686 | + |
687 | +import ( |
688 | + "fmt" |
689 | + "io" |
690 | + "math" |
691 | + "strings" |
692 | + "sync/atomic" |
693 | + "time" |
694 | +) |
695 | + |
696 | +const ( |
697 | + // Default refresh rate - 200ms |
698 | + DEFAULT_REFRESH_RATE = time.Millisecond * 200 |
699 | + FORMAT = "[=>-]" |
700 | +) |
701 | + |
702 | +// DEPRECATED |
703 | +// variables for backward compatibility, from now do not work |
704 | +// use pb.Format and pb.SetRefreshRate |
705 | +var ( |
706 | + DefaultRefreshRate = DEFAULT_REFRESH_RATE |
707 | + BarStart, BarEnd, Empty, Current, CurrentN string |
708 | +) |
709 | + |
710 | +// Create new progress bar object |
711 | +func New(total int) (pb *ProgressBar) { |
712 | + return New64(int64(total)) |
713 | +} |
714 | + |
715 | +// Create new progress bar object uding int64 as total |
716 | +func New64(total int64) (pb *ProgressBar) { |
717 | + pb = &ProgressBar{ |
718 | + Total: total, |
719 | + RefreshRate: DEFAULT_REFRESH_RATE, |
720 | + ShowPercent: true, |
721 | + ShowCounters: true, |
722 | + ShowBar: true, |
723 | + ShowTimeLeft: true, |
724 | + ShowFinalTime: true, |
725 | + ManualUpdate: false, |
726 | + currentValue: -1, |
727 | + } |
728 | + pb.Format(FORMAT) |
729 | + return |
730 | +} |
731 | + |
732 | +// Create new object and start |
733 | +func StartNew(total int) (pb *ProgressBar) { |
734 | + pb = New(total) |
735 | + pb.Start() |
736 | + return |
737 | +} |
738 | + |
739 | +// Callback for custom output |
740 | +// For example: |
741 | +// bar.Callback = func(s string) { |
742 | +// mySuperPrint(s) |
743 | +// } |
744 | +// |
745 | +type Callback func(out string) |
746 | + |
747 | +type ProgressBar struct { |
748 | + current int64 // current must be first member of struct (https://code.google.com/p/go/issues/detail?id=5278) |
749 | + |
750 | + Total int64 |
751 | + RefreshRate time.Duration |
752 | + ShowPercent, ShowCounters bool |
753 | + ShowSpeed, ShowTimeLeft, ShowBar bool |
754 | + ShowFinalTime bool |
755 | + Output io.Writer |
756 | + Callback Callback |
757 | + NotPrint bool |
758 | + Units int |
759 | + Width int |
760 | + ForceWidth bool |
761 | + ManualUpdate bool |
762 | + |
763 | + isFinish bool |
764 | + startTime time.Time |
765 | + currentValue int64 |
766 | + |
767 | + prefix, postfix string |
768 | + |
769 | + BarStart string |
770 | + BarEnd string |
771 | + Empty string |
772 | + Current string |
773 | + CurrentN string |
774 | +} |
775 | + |
776 | +// Start print |
777 | +func (pb *ProgressBar) Start() { |
778 | + pb.startTime = time.Now() |
779 | + if pb.Total == 0 { |
780 | + pb.ShowBar = false |
781 | + pb.ShowTimeLeft = false |
782 | + pb.ShowPercent = false |
783 | + } |
784 | + if !pb.ManualUpdate { |
785 | + go pb.writer() |
786 | + } |
787 | +} |
788 | + |
789 | +// Increment current value |
790 | +func (pb *ProgressBar) Increment() int { |
791 | + return pb.Add(1) |
792 | +} |
793 | + |
794 | +// Set current value |
795 | +func (pb *ProgressBar) Set(current int) { |
796 | + atomic.StoreInt64(&pb.current, int64(current)) |
797 | +} |
798 | + |
799 | +// Add to current value |
800 | +func (pb *ProgressBar) Add(add int) int { |
801 | + return int(pb.Add64(int64(add))) |
802 | +} |
803 | + |
804 | +func (pb *ProgressBar) Add64(add int64) int64 { |
805 | + return atomic.AddInt64(&pb.current, add) |
806 | +} |
807 | + |
808 | +// Set prefix string |
809 | +func (pb *ProgressBar) Prefix(prefix string) (bar *ProgressBar) { |
810 | + pb.prefix = prefix |
811 | + return pb |
812 | +} |
813 | + |
814 | +// Set postfix string |
815 | +func (pb *ProgressBar) Postfix(postfix string) (bar *ProgressBar) { |
816 | + pb.postfix = postfix |
817 | + return pb |
818 | +} |
819 | + |
820 | +// Set custom format for bar |
821 | +// Example: bar.Format("[=>_]") |
822 | +func (pb *ProgressBar) Format(format string) (bar *ProgressBar) { |
823 | + bar = pb |
824 | + formatEntries := strings.Split(format, "") |
825 | + if len(formatEntries) != 5 { |
826 | + return |
827 | + } |
828 | + pb.BarStart = formatEntries[0] |
829 | + pb.BarEnd = formatEntries[4] |
830 | + pb.Empty = formatEntries[3] |
831 | + pb.Current = formatEntries[1] |
832 | + pb.CurrentN = formatEntries[2] |
833 | + return |
834 | +} |
835 | + |
836 | +// Set bar refresh rate |
837 | +func (pb *ProgressBar) SetRefreshRate(rate time.Duration) (bar *ProgressBar) { |
838 | + bar = pb |
839 | + pb.RefreshRate = rate |
840 | + return |
841 | +} |
842 | + |
843 | +// Set units |
844 | +// bar.SetUnits(U_NO) - by default |
845 | +// bar.SetUnits(U_BYTES) - for Mb, Kb, etc |
846 | +func (pb *ProgressBar) SetUnits(units int) (bar *ProgressBar) { |
847 | + bar = pb |
848 | + switch units { |
849 | + case U_NO, U_BYTES: |
850 | + pb.Units = units |
851 | + } |
852 | + return |
853 | +} |
854 | + |
855 | +// Set max width, if width is bigger than terminal width, will be ignored |
856 | +func (pb *ProgressBar) SetMaxWidth(width int) (bar *ProgressBar) { |
857 | + bar = pb |
858 | + pb.Width = width |
859 | + pb.ForceWidth = false |
860 | + return |
861 | +} |
862 | + |
863 | +// Set bar width |
864 | +func (pb *ProgressBar) SetWidth(width int) (bar *ProgressBar) { |
865 | + bar = pb |
866 | + pb.Width = width |
867 | + pb.ForceWidth = true |
868 | + return |
869 | +} |
870 | + |
871 | +// End print |
872 | +func (pb *ProgressBar) Finish() { |
873 | + pb.isFinish = true |
874 | + pb.write(atomic.LoadInt64(&pb.current)) |
875 | + if !pb.NotPrint { |
876 | + fmt.Println() |
877 | + } |
878 | +} |
879 | + |
880 | +// End print and write string 'str' |
881 | +func (pb *ProgressBar) FinishPrint(str string) { |
882 | + pb.Finish() |
883 | + fmt.Println(str) |
884 | +} |
885 | + |
886 | +// implement io.Writer |
887 | +func (pb *ProgressBar) Write(p []byte) (n int, err error) { |
888 | + n = len(p) |
889 | + pb.Add(n) |
890 | + return |
891 | +} |
892 | + |
893 | +// implement io.Reader |
894 | +func (pb *ProgressBar) Read(p []byte) (n int, err error) { |
895 | + n = len(p) |
896 | + pb.Add(n) |
897 | + return |
898 | +} |
899 | + |
900 | +// Create new proxy reader over bar |
901 | +func (pb *ProgressBar) NewProxyReader(r io.Reader) *Reader { |
902 | + return &Reader{r, pb} |
903 | +} |
904 | + |
905 | +func (pb *ProgressBar) write(current int64) { |
906 | + width := pb.getWidth() |
907 | + |
908 | + var percentBox, countersBox, timeLeftBox, speedBox, barBox, end, out string |
909 | + |
910 | + // percents |
911 | + if pb.ShowPercent { |
912 | + percent := float64(current) / (float64(pb.Total) / float64(100)) |
913 | + percentBox = fmt.Sprintf(" %#.02f %% ", percent) |
914 | + } |
915 | + |
916 | + // counters |
917 | + if pb.ShowCounters { |
918 | + if pb.Total > 0 { |
919 | + countersBox = fmt.Sprintf("%s / %s ", Format(current, pb.Units), Format(pb.Total, pb.Units)) |
920 | + } else { |
921 | + countersBox = Format(current, pb.Units) + " " |
922 | + } |
923 | + } |
924 | + |
925 | + // time left |
926 | + fromStart := time.Now().Sub(pb.startTime) |
927 | + if pb.isFinish { |
928 | + if pb.ShowFinalTime { |
929 | + left := (fromStart / time.Second) * time.Second |
930 | + timeLeftBox = left.String() |
931 | + } |
932 | + } else if pb.ShowTimeLeft && current > 0 { |
933 | + perEntry := fromStart / time.Duration(current) |
934 | + left := time.Duration(pb.Total-current) * perEntry |
935 | + left = (left / time.Second) * time.Second |
936 | + timeLeftBox = left.String() |
937 | + } |
938 | + |
939 | + // speed |
940 | + if pb.ShowSpeed && current > 0 { |
941 | + fromStart := time.Now().Sub(pb.startTime) |
942 | + speed := float64(current) / (float64(fromStart) / float64(time.Second)) |
943 | + speedBox = Format(int64(speed), pb.Units) + "/s " |
944 | + } |
945 | + |
946 | + // bar |
947 | + if pb.ShowBar { |
948 | + size := width - len(countersBox+pb.BarStart+pb.BarEnd+percentBox+timeLeftBox+speedBox+pb.prefix+pb.postfix) |
949 | + if size > 0 { |
950 | + curCount := int(math.Ceil((float64(current) / float64(pb.Total)) * float64(size))) |
951 | + emptCount := size - curCount |
952 | + barBox = pb.BarStart |
953 | + if emptCount < 0 { |
954 | + emptCount = 0 |
955 | + } |
956 | + if curCount > size { |
957 | + curCount = size |
958 | + } |
959 | + if emptCount <= 0 { |
960 | + barBox += strings.Repeat(pb.Current, curCount) |
961 | + } else if curCount > 0 { |
962 | + barBox += strings.Repeat(pb.Current, curCount-1) + pb.CurrentN |
963 | + } |
964 | + |
965 | + barBox += strings.Repeat(pb.Empty, emptCount) + pb.BarEnd |
966 | + } |
967 | + } |
968 | + |
969 | + // check len |
970 | + out = pb.prefix + countersBox + barBox + percentBox + speedBox + timeLeftBox + pb.postfix |
971 | + if len(out) < width { |
972 | + end = strings.Repeat(" ", width-len(out)) |
973 | + } |
974 | + |
975 | + // and print! |
976 | + switch { |
977 | + case pb.Output != nil: |
978 | + fmt.Fprint(pb.Output, "\r"+out+end) |
979 | + case pb.Callback != nil: |
980 | + pb.Callback(out + end) |
981 | + case !pb.NotPrint: |
982 | + fmt.Print("\r" + out + end) |
983 | + } |
984 | +} |
985 | + |
986 | +func (pb *ProgressBar) getWidth() int { |
987 | + if pb.ForceWidth { |
988 | + return pb.Width |
989 | + } |
990 | + |
991 | + width := pb.Width |
992 | + termWidth, _ := terminalWidth() |
993 | + if width == 0 || termWidth <= width { |
994 | + width = termWidth |
995 | + } |
996 | + |
997 | + return width |
998 | +} |
999 | + |
1000 | +// Write the current state of the progressbar |
1001 | +func (pb *ProgressBar) Update() { |
1002 | + c := atomic.LoadInt64(&pb.current) |
1003 | + if c != pb.currentValue { |
1004 | + pb.write(c) |
1005 | + pb.currentValue = c |
1006 | + } |
1007 | +} |
1008 | + |
1009 | +// Internal loop for writing progressbar |
1010 | +func (pb *ProgressBar) writer() { |
1011 | + for { |
1012 | + if pb.isFinish { |
1013 | + break |
1014 | + } |
1015 | + pb.Update() |
1016 | + time.Sleep(pb.RefreshRate) |
1017 | + } |
1018 | +} |
1019 | + |
1020 | +type window struct { |
1021 | + Row uint16 |
1022 | + Col uint16 |
1023 | + Xpixel uint16 |
1024 | + Ypixel uint16 |
1025 | +} |
1026 | |
1027 | === added file 'internal/github.com/cheggaaa/pb/pb_nix.go' |
1028 | --- internal/github.com/cheggaaa/pb/pb_nix.go 1970-01-01 00:00:00 +0000 |
1029 | +++ internal/github.com/cheggaaa/pb/pb_nix.go 2015-10-30 14:12:15 +0000 |
1030 | @@ -0,0 +1,7 @@ |
1031 | +// +build linux darwin freebsd openbsd |
1032 | + |
1033 | +package pb |
1034 | + |
1035 | +import "syscall" |
1036 | + |
1037 | +const sys_ioctl = syscall.SYS_IOCTL |
1038 | |
1039 | === added file 'internal/github.com/cheggaaa/pb/pb_solaris.go' |
1040 | --- internal/github.com/cheggaaa/pb/pb_solaris.go 1970-01-01 00:00:00 +0000 |
1041 | +++ internal/github.com/cheggaaa/pb/pb_solaris.go 2015-10-30 14:12:15 +0000 |
1042 | @@ -0,0 +1,5 @@ |
1043 | +// +build solaris |
1044 | + |
1045 | +package pb |
1046 | + |
1047 | +const sys_ioctl = 54 |
1048 | |
1049 | === added file 'internal/github.com/cheggaaa/pb/pb_test.go' |
1050 | --- internal/github.com/cheggaaa/pb/pb_test.go 1970-01-01 00:00:00 +0000 |
1051 | +++ internal/github.com/cheggaaa/pb/pb_test.go 2015-10-30 14:12:15 +0000 |
1052 | @@ -0,0 +1,30 @@ |
1053 | +package pb |
1054 | + |
1055 | +import ( |
1056 | + "testing" |
1057 | +) |
1058 | + |
1059 | +func Test_IncrementAddsOne(t *testing.T) { |
1060 | + count := 5000 |
1061 | + bar := New(count) |
1062 | + expected := 1 |
1063 | + actual := bar.Increment() |
1064 | + |
1065 | + if actual != expected { |
1066 | + t.Errorf("Expected {%d} was {%d}", expected, actual) |
1067 | + } |
1068 | +} |
1069 | + |
1070 | +func Test_Width(t *testing.T) { |
1071 | + count := 5000 |
1072 | + bar := New(count) |
1073 | + width := 100 |
1074 | + bar.SetWidth(100).Callback = func(out string) { |
1075 | + if len(out) != width { |
1076 | + t.Errorf("Bar width expected {%d} was {%d}", len(out), width) |
1077 | + } |
1078 | + } |
1079 | + bar.Start() |
1080 | + bar.Increment() |
1081 | + bar.Finish() |
1082 | +} |
1083 | |
1084 | === added file 'internal/github.com/cheggaaa/pb/pb_win.go' |
1085 | --- internal/github.com/cheggaaa/pb/pb_win.go 1970-01-01 00:00:00 +0000 |
1086 | +++ internal/github.com/cheggaaa/pb/pb_win.go 2015-10-30 14:12:15 +0000 |
1087 | @@ -0,0 +1,16 @@ |
1088 | +// +build windows |
1089 | + |
1090 | +package pb |
1091 | + |
1092 | +import ( |
1093 | + "launchpad.net/crackly/internal/github.com/olekukonko/ts" |
1094 | +) |
1095 | + |
1096 | +func bold(str string) string { |
1097 | + return str |
1098 | +} |
1099 | + |
1100 | +func terminalWidth() (int, error) { |
1101 | + size, err := ts.GetSize() |
1102 | + return size.Col(), err |
1103 | +} |
1104 | |
1105 | === added file 'internal/github.com/cheggaaa/pb/pb_x.go' |
1106 | --- internal/github.com/cheggaaa/pb/pb_x.go 1970-01-01 00:00:00 +0000 |
1107 | +++ internal/github.com/cheggaaa/pb/pb_x.go 2015-10-30 14:12:15 +0000 |
1108 | @@ -0,0 +1,46 @@ |
1109 | +// +build linux darwin freebsd openbsd solaris |
1110 | + |
1111 | +package pb |
1112 | + |
1113 | +import ( |
1114 | + "os" |
1115 | + "runtime" |
1116 | + "syscall" |
1117 | + "unsafe" |
1118 | +) |
1119 | + |
1120 | +const ( |
1121 | + TIOCGWINSZ = 0x5413 |
1122 | + TIOCGWINSZ_OSX = 1074295912 |
1123 | +) |
1124 | + |
1125 | +var tty *os.File |
1126 | + |
1127 | +func init() { |
1128 | + var err error |
1129 | + tty, err = os.Open("/dev/tty") |
1130 | + if err != nil { |
1131 | + tty = os.Stdin |
1132 | + } |
1133 | +} |
1134 | + |
1135 | +func bold(str string) string { |
1136 | + return "\033[1m" + str + "\033[0m" |
1137 | +} |
1138 | + |
1139 | +func terminalWidth() (int, error) { |
1140 | + w := new(window) |
1141 | + tio := syscall.TIOCGWINSZ |
1142 | + if runtime.GOOS == "darwin" { |
1143 | + tio = TIOCGWINSZ_OSX |
1144 | + } |
1145 | + res, _, err := syscall.Syscall(sys_ioctl, |
1146 | + tty.Fd(), |
1147 | + uintptr(tio), |
1148 | + uintptr(unsafe.Pointer(w)), |
1149 | + ) |
1150 | + if int(res) == -1 { |
1151 | + return 0, err |
1152 | + } |
1153 | + return int(w.Col), nil |
1154 | +} |
1155 | |
1156 | === added file 'internal/github.com/cheggaaa/pb/reader.go' |
1157 | --- internal/github.com/cheggaaa/pb/reader.go 1970-01-01 00:00:00 +0000 |
1158 | +++ internal/github.com/cheggaaa/pb/reader.go 2015-10-30 14:12:15 +0000 |
1159 | @@ -0,0 +1,17 @@ |
1160 | +package pb |
1161 | + |
1162 | +import ( |
1163 | + "io" |
1164 | +) |
1165 | + |
1166 | +// It's proxy reader, implement io.Reader |
1167 | +type Reader struct { |
1168 | + io.Reader |
1169 | + bar *ProgressBar |
1170 | +} |
1171 | + |
1172 | +func (r *Reader) Read(p []byte) (n int, err error) { |
1173 | + n, err = r.Reader.Read(p) |
1174 | + r.bar.Add(n) |
1175 | + return |
1176 | +} |
1177 | |
1178 | === added directory 'internal/github.com/gosexy' |
1179 | === added directory 'internal/github.com/gosexy/gettext' |
1180 | === added file 'internal/github.com/gosexy/gettext/LICENSE' |
1181 | --- internal/github.com/gosexy/gettext/LICENSE 1970-01-01 00:00:00 +0000 |
1182 | +++ internal/github.com/gosexy/gettext/LICENSE 2015-10-30 14:12:15 +0000 |
1183 | @@ -0,0 +1,20 @@ |
1184 | +Copyright (c) 2012-2013 José Carlos Nieto, http://xiam.menteslibres.org/ |
1185 | + |
1186 | +Permission is hereby granted, free of charge, to any person obtaining |
1187 | +a copy of this software and associated documentation files (the |
1188 | +"Software"), to deal in the Software without restriction, including |
1189 | +without limitation the rights to use, copy, modify, merge, publish, |
1190 | +distribute, sublicense, and/or sell copies of the Software, and to |
1191 | +permit persons to whom the Software is furnished to do so, subject to |
1192 | +the following conditions: |
1193 | + |
1194 | +The above copyright notice and this permission notice shall be |
1195 | +included in all copies or substantial portions of the Software. |
1196 | + |
1197 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
1198 | +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
1199 | +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
1200 | +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
1201 | +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
1202 | +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
1203 | +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
1204 | |
1205 | === added file 'internal/github.com/gosexy/gettext/README.md' |
1206 | --- internal/github.com/gosexy/gettext/README.md 1970-01-01 00:00:00 +0000 |
1207 | +++ internal/github.com/gosexy/gettext/README.md 2015-10-30 14:12:15 +0000 |
1208 | @@ -0,0 +1,94 @@ |
1209 | +# gosexy/gettext |
1210 | + |
1211 | +Go bindings for [GNU gettext][1], an internationalization and localization |
1212 | +library for writing multilingual systems. |
1213 | + |
1214 | +## Requeriments |
1215 | + |
1216 | +The GNU C library. If you're using GNU/Linux, FreeBSD or OSX you should already |
1217 | +have it. |
1218 | + |
1219 | +## Installation |
1220 | + |
1221 | +Use `go get` to download and install the binding: |
1222 | + |
1223 | +```sh |
1224 | +go get github.com/gosexy/gettext |
1225 | +``` |
1226 | + |
1227 | +## Usage |
1228 | + |
1229 | +```go |
1230 | +package main |
1231 | + |
1232 | +import ( |
1233 | + "github.com/gosexy/gettext" |
1234 | + "fmt" |
1235 | + "os" |
1236 | +) |
1237 | + |
1238 | +func main() { |
1239 | + gettext.BindTextdomain("example", ".") |
1240 | + gettext.Textdomain("example") |
1241 | + |
1242 | + os.Setenv("LANGUAGE", "es_MX.utf8") |
1243 | + |
1244 | + gettext.SetLocale(gettext.LC_ALL, "") |
1245 | + |
1246 | + fmt.Println(gettext.Gettext("Hello, world!")) |
1247 | +} |
1248 | +``` |
1249 | + |
1250 | +You can use `os.Setenv` to set the `LANGUAGE` environment variable or set it |
1251 | +on a terminal: |
1252 | + |
1253 | +```sh |
1254 | +export LANGUAGE="es_MX.utf8" |
1255 | +./gettext-program |
1256 | +``` |
1257 | + |
1258 | +Note that `xgettext` does not officially support Go syntax yet, however, you |
1259 | +can generate a valid `.pot` file by forcing `xgettest` to use the C++ |
1260 | +syntax: |
1261 | + |
1262 | +```sh |
1263 | +xgettext -d example -s gettext_test.go -o example.pot -L c++ -i \ |
1264 | +--keyword=NGettext:1,2 --keyword=Gettext |
1265 | +``` |
1266 | + |
1267 | +This will generate a `example.pot` file. |
1268 | + |
1269 | +After translating the `.pot` file, you must generate `.po` and `.mo` files and |
1270 | +remember to set the UTF-8 charset. |
1271 | + |
1272 | +```sh |
1273 | +msginit -l es_MX -o example.po -i example.pot |
1274 | +msgfmt -c -v -o example.mo example.po |
1275 | +``` |
1276 | + |
1277 | +Finally, move the `.mo` file to an appropriate location. |
1278 | + |
1279 | +```sh |
1280 | +mv example.mo examples/es_MX.utf8/LC_MESSAGES/example.mo |
1281 | +``` |
1282 | + |
1283 | +## Documentation |
1284 | + |
1285 | +You can read `gosexy/gettext` documentation from a terminal |
1286 | + |
1287 | +```sh |
1288 | +go doc github.com/gosexy/gettext |
1289 | +``` |
1290 | + |
1291 | +Or you can [browse it](http://godoc.org/github.com/gosexy/gettext) online. |
1292 | + |
1293 | +The original gettext documentation could be very useful as well: |
1294 | + |
1295 | +```sh |
1296 | +man 3 gettext |
1297 | +``` |
1298 | + |
1299 | +Here's another [good tutorial][2] on using gettext. |
1300 | + |
1301 | +[1]: http://www.gnu.org/software/gettext/ |
1302 | +[2]: http://oriya.sarovar.org/docs/gettext_single.html |
1303 | |
1304 | === added file 'internal/github.com/gosexy/gettext/gettext.go' |
1305 | --- internal/github.com/gosexy/gettext/gettext.go 1970-01-01 00:00:00 +0000 |
1306 | +++ internal/github.com/gosexy/gettext/gettext.go 2015-10-30 14:12:15 +0000 |
1307 | @@ -0,0 +1,207 @@ |
1308 | +/* |
1309 | + Copyright (c) 2012 José Carlos Nieto, http://xiam.menteslibres.org/ |
1310 | + |
1311 | + Permission is hereby granted, free of charge, to any person obtaining |
1312 | + a copy of this software and associated documentation files (the |
1313 | + "Software"), to deal in the Software without restriction, including |
1314 | + without limitation the rights to use, copy, modify, merge, publish, |
1315 | + distribute, sublicense, and/or sell copies of the Software, and to |
1316 | + permit persons to whom the Software is furnished to do so, subject to |
1317 | + the following conditions: |
1318 | + |
1319 | + The above copyright notice and this permission notice shall be |
1320 | + included in all copies or substantial portions of the Software. |
1321 | + |
1322 | + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
1323 | + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
1324 | + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
1325 | + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
1326 | + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
1327 | + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
1328 | + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
1329 | +*/ |
1330 | + |
1331 | +package gettext |
1332 | + |
1333 | +/* |
1334 | + |
1335 | +#include <libintl.h> |
1336 | +#include <locale.h> |
1337 | +#include <stdlib.h> |
1338 | +*/ |
1339 | +import "C" |
1340 | + |
1341 | +import ( |
1342 | + "fmt" |
1343 | + "strings" |
1344 | + "unsafe" |
1345 | +) |
1346 | + |
1347 | +var ( |
1348 | + // For all of the locale. |
1349 | + LC_ALL = uint(C.LC_ALL) |
1350 | + |
1351 | + // For regular expression matching (it determines the meaning of range |
1352 | + // expressions and equivalence classes) and string collation. |
1353 | + LC_COLATE = uint(C.LC_ALL) |
1354 | + |
1355 | + // For regular expression matching, character classification, conversion, |
1356 | + // case-sensitive comparison, and wide character functions. |
1357 | + LC_CTYPE = uint(C.LC_CTYPE) |
1358 | + |
1359 | + // For localizable natural-language messages. |
1360 | + LC_MESSAGES = uint(C.LC_MESSAGES) |
1361 | + |
1362 | + // For monetary formatting. |
1363 | + LC_MONETARY = uint(C.LC_MONETARY) |
1364 | + |
1365 | + // For number formatting (such as the decimal point and the thousands |
1366 | + // separator). |
1367 | + LC_NUMERIC = uint(C.LC_NUMERIC) |
1368 | + |
1369 | + // For time and date formatting. |
1370 | + LC_TIME = uint(C.LC_TIME) |
1371 | +) |
1372 | + |
1373 | +// Sets or queries the program's current locale. |
1374 | +func SetLocale(category uint, locale string) string { |
1375 | + clocale := C.CString(locale) |
1376 | + |
1377 | + res := C.GoString(C.setlocale(C.int(category), clocale)) |
1378 | + |
1379 | + C.free(unsafe.Pointer(clocale)) |
1380 | + return res |
1381 | +} |
1382 | + |
1383 | +// Sets directory containing message catalogs. |
1384 | +func BindTextdomain(domainname string, dirname string) string { |
1385 | + cdirname := C.CString(dirname) |
1386 | + cdomainname := C.CString(domainname) |
1387 | + |
1388 | + res := C.GoString(C.bindtextdomain(cdomainname, cdirname)) |
1389 | + |
1390 | + C.free(unsafe.Pointer(cdirname)) |
1391 | + C.free(unsafe.Pointer(cdomainname)) |
1392 | + return res |
1393 | +} |
1394 | + |
1395 | +// Sets the output codeset for message catalogs for domain domainname. |
1396 | +func BindTextdomainCodeset(domainname string, codeset string) string { |
1397 | + cdomainname := C.CString(domainname) |
1398 | + ccodeset := C.CString(codeset) |
1399 | + |
1400 | + res := C.GoString(C.bind_textdomain_codeset(cdomainname, ccodeset)) |
1401 | + |
1402 | + C.free(unsafe.Pointer(cdomainname)) |
1403 | + C.free(unsafe.Pointer(ccodeset)) |
1404 | + return res |
1405 | +} |
1406 | + |
1407 | +// Sets or retrieves the current message domain. |
1408 | +func Textdomain(domainname string) string { |
1409 | + cdomainname := C.CString(domainname) |
1410 | + |
1411 | + res := C.GoString(C.textdomain(cdomainname)) |
1412 | + |
1413 | + C.free(unsafe.Pointer(cdomainname)) |
1414 | + return res |
1415 | +} |
1416 | + |
1417 | +// Attempt to translate a text string into the user's native language, by |
1418 | +// looking up the translation in a message catalog. |
1419 | +func Gettext(msgid string) string { |
1420 | + cmsgid := C.CString(msgid) |
1421 | + |
1422 | + res := C.GoString(C.gettext(cmsgid)) |
1423 | + |
1424 | + C.free(unsafe.Pointer(cmsgid)) |
1425 | + return res |
1426 | +} |
1427 | + |
1428 | +// Like Gettext(), but looking up the message in the specified domain. |
1429 | +func DGettext(domain string, msgid string) string { |
1430 | + cdomain := C.CString(domain) |
1431 | + cmsgid := C.CString(msgid) |
1432 | + |
1433 | + res := C.GoString(C.dgettext(cdomain, cmsgid)) |
1434 | + |
1435 | + C.free(unsafe.Pointer(cdomain)) |
1436 | + C.free(unsafe.Pointer(cmsgid)) |
1437 | + return res |
1438 | +} |
1439 | + |
1440 | +// Like Gettext(), but looking up the message in the specified domain and |
1441 | +// category. |
1442 | +func DCGettext(domain string, msgid string, category uint) string { |
1443 | + cdomain := C.CString(domain) |
1444 | + cmsgid := C.CString(msgid) |
1445 | + |
1446 | + res := C.GoString(C.dcgettext(cdomain, cmsgid, C.int(category))) |
1447 | + |
1448 | + C.free(unsafe.Pointer(cdomain)) |
1449 | + C.free(unsafe.Pointer(cmsgid)) |
1450 | + return res |
1451 | +} |
1452 | + |
1453 | +// Attempt to translate a text string into the user's native language, by |
1454 | +// looking up the appropriate plural form of the translation in a message |
1455 | +// catalog. |
1456 | +func NGettext(msgid string, msgid_plural string, n uint64) string { |
1457 | + cmsgid := C.CString(msgid) |
1458 | + cmsgid_plural := C.CString(msgid_plural) |
1459 | + |
1460 | + res := C.GoString(C.ngettext(cmsgid, cmsgid_plural, C.ulong(n))) |
1461 | + |
1462 | + C.free(unsafe.Pointer(cmsgid)) |
1463 | + C.free(unsafe.Pointer(cmsgid_plural)) |
1464 | + |
1465 | + return res |
1466 | +} |
1467 | + |
1468 | +// Like fmt.Sprintf() but without %!(EXTRA) errors. |
1469 | +func Sprintf(format string, a ...interface{}) string { |
1470 | + expects := strings.Count(format, "%") - strings.Count(format, "%%") |
1471 | + |
1472 | + if expects > 0 { |
1473 | + arguments := make([]interface{}, expects) |
1474 | + for i := 0; i < expects; i++ { |
1475 | + if len(a) > i { |
1476 | + arguments[i] = a[i] |
1477 | + } |
1478 | + } |
1479 | + return fmt.Sprintf(format, arguments...) |
1480 | + } |
1481 | + |
1482 | + return format |
1483 | +} |
1484 | + |
1485 | +// Like NGettext(), but looking up the message in the specified domain. |
1486 | +func DNGettext(domainname string, msgid string, msgid_plural string, n uint64) string { |
1487 | + cdomainname := C.CString(domainname) |
1488 | + cmsgid := C.CString(msgid) |
1489 | + cmsgid_plural := C.CString(msgid_plural) |
1490 | + |
1491 | + res := C.GoString(C.dngettext(cdomainname, cmsgid, cmsgid_plural, C.ulong(n))) |
1492 | + |
1493 | + C.free(unsafe.Pointer(cdomainname)) |
1494 | + C.free(unsafe.Pointer(cmsgid)) |
1495 | + C.free(unsafe.Pointer(cmsgid_plural)) |
1496 | + |
1497 | + return res |
1498 | +} |
1499 | + |
1500 | +// Like NGettext(), but looking up the message in the specified domain and |
1501 | +// category. |
1502 | +func DCNGettext(domainname string, msgid string, msgid_plural string, n uint64, category uint) string { |
1503 | + cdomainname := C.CString(domainname) |
1504 | + cmsgid := C.CString(msgid) |
1505 | + cmsgid_plural := C.CString(msgid_plural) |
1506 | + |
1507 | + res := C.GoString(C.dcngettext(cdomainname, cmsgid, cmsgid_plural, C.ulong(n), C.int(category))) |
1508 | + |
1509 | + C.free(unsafe.Pointer(cdomainname)) |
1510 | + C.free(unsafe.Pointer(cmsgid)) |
1511 | + C.free(unsafe.Pointer(cmsgid_plural)) |
1512 | + |
1513 | + return res |
1514 | +} |
1515 | |
1516 | === added file 'internal/github.com/gosexy/gettext/gettext_test.go' |
1517 | --- internal/github.com/gosexy/gettext/gettext_test.go 1970-01-01 00:00:00 +0000 |
1518 | +++ internal/github.com/gosexy/gettext/gettext_test.go 2015-10-30 14:12:15 +0000 |
1519 | @@ -0,0 +1,130 @@ |
1520 | +package gettext |
1521 | + |
1522 | +import ( |
1523 | + "fmt" |
1524 | + "os" |
1525 | + "testing" |
1526 | +) |
1527 | + |
1528 | +/* |
1529 | + NOTE: |
1530 | + |
1531 | + xgettext does not officially support Go syntax, however, you can generate a valid .pot file by forcing |
1532 | + xgettest to use the C++ syntax: |
1533 | + |
1534 | + % xgettext -d example -s gettext_test.go -o example.pot -L c++ -i --keyword=NGettext:1,2 --keyword=Gettext |
1535 | + |
1536 | + This will generate a example.pot file. |
1537 | + |
1538 | + After translating the .pot file, you must generate .po and .mo files. |
1539 | + |
1540 | + Remember to set the UTF-8 charset. |
1541 | + |
1542 | + % msginit -l es_MX -o example.po -i example.pot |
1543 | + % msgfmt -c -v -o example.mo example.po |
1544 | + |
1545 | + And finally, move the .mo file to an appropriate location. |
1546 | + |
1547 | + % mv example.mo examples/es_MX.utf8/LC_MESSAGES/example.mo |
1548 | + |
1549 | +*/ |
1550 | + |
1551 | +func TestSpanishMexico(t *testing.T) { |
1552 | + |
1553 | + os.Setenv("LANGUAGE", "es_MX.utf8") |
1554 | + |
1555 | + SetLocale(LC_ALL, "") |
1556 | + BindTextdomain("example", "./examples/") |
1557 | + Textdomain("example") |
1558 | + |
1559 | + t1 := Gettext("Hello, world!") |
1560 | + |
1561 | + fmt.Println(t1) |
1562 | + |
1563 | + if t1 != "¡Hola mundo!" { |
1564 | + t.Errorf("Failed translation.") |
1565 | + } |
1566 | + |
1567 | + t2 := Sprintf(NGettext("An apple", "%d apples", 1), 1, "garbage") |
1568 | + |
1569 | + fmt.Println(t2) |
1570 | + |
1571 | + if t2 != "Una manzana" { |
1572 | + t.Errorf("Failed translation.") |
1573 | + } |
1574 | + |
1575 | + t3 := Sprintf(NGettext("An apple", "%d apples", 3), 3) |
1576 | + |
1577 | + fmt.Println(t3) |
1578 | + |
1579 | + if t3 != "3 manzanas" { |
1580 | + t.Errorf("Failed translation.") |
1581 | + } |
1582 | + |
1583 | + t4 := Gettext("Good morning") |
1584 | + |
1585 | + fmt.Println(t4) |
1586 | + |
1587 | + if t4 != "Buenos dÃas" { |
1588 | + t.Errorf("Failed translation.") |
1589 | + } |
1590 | + |
1591 | + t5 := Gettext("Good bye!") |
1592 | + |
1593 | + fmt.Println(t5) |
1594 | + |
1595 | + if t5 != "¡Hasta luego!" { |
1596 | + t.Errorf("Failed translation.") |
1597 | + } |
1598 | + |
1599 | +} |
1600 | + |
1601 | +func TestGermanDeutschland(t *testing.T) { |
1602 | + |
1603 | + os.Setenv("LANGUAGE", "de_DE.utf8") |
1604 | + |
1605 | + SetLocale(LC_ALL, "") |
1606 | + BindTextdomain("example", "./examples/") |
1607 | + Textdomain("example") |
1608 | + |
1609 | + t1 := Gettext("Hello, world!") |
1610 | + |
1611 | + fmt.Println(t1) |
1612 | + |
1613 | + if t1 != "Hallo, Welt!" { |
1614 | + t.Errorf("Failed translation.") |
1615 | + } |
1616 | + |
1617 | + t2 := Sprintf(NGettext("An apple", "%d apples", 1), 1, "garbage") |
1618 | + |
1619 | + fmt.Println(t2) |
1620 | + |
1621 | + if t2 != "Ein Apfel" { |
1622 | + t.Errorf("Failed translation.") |
1623 | + } |
1624 | + |
1625 | + t3 := Sprintf(NGettext("An apple", "%d apples", 3), 3) |
1626 | + |
1627 | + fmt.Println(t3) |
1628 | + |
1629 | + if t3 != "3 Äpfel" { |
1630 | + t.Errorf("Failed translation.") |
1631 | + } |
1632 | + |
1633 | + t4 := Gettext("Good morning") |
1634 | + |
1635 | + fmt.Println(t4) |
1636 | + |
1637 | + if t4 != "Guten morgen" { |
1638 | + t.Errorf("Failed translation.") |
1639 | + } |
1640 | + |
1641 | + t5 := Gettext("Good bye!") |
1642 | + |
1643 | + fmt.Println(t5) |
1644 | + |
1645 | + if t5 != "Aufwiedersehen!" { |
1646 | + t.Errorf("Failed translation.") |
1647 | + } |
1648 | + |
1649 | +} |
1650 | |
1651 | === added directory 'internal/github.com/mvo5' |
1652 | === added directory 'internal/github.com/mvo5/goconfigparser' |
1653 | === added file 'internal/github.com/mvo5/goconfigparser/COPYING' |
1654 | --- internal/github.com/mvo5/goconfigparser/COPYING 1970-01-01 00:00:00 +0000 |
1655 | +++ internal/github.com/mvo5/goconfigparser/COPYING 2015-10-30 14:12:15 +0000 |
1656 | @@ -0,0 +1,19 @@ |
1657 | +Copyright (c) 2014 Canonical |
1658 | + |
1659 | +Permission is hereby granted, free of charge, to any person obtaining a copy |
1660 | +of this software and associated documentation files (the "Software"), to deal |
1661 | +in the Software without restriction, including without limitation the rights |
1662 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
1663 | +copies of the Software, and to permit persons to whom the Software is |
1664 | +furnished to do so, subject to the following conditions: |
1665 | +. |
1666 | +The above copyright notice and this permission notice shall be included in |
1667 | +all copies or substantial portions of the Software. |
1668 | +. |
1669 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
1670 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
1671 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
1672 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
1673 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
1674 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
1675 | +THE SOFTWARE. |
1676 | |
1677 | === added file 'internal/github.com/mvo5/goconfigparser/README.md' |
1678 | --- internal/github.com/mvo5/goconfigparser/README.md 1970-01-01 00:00:00 +0000 |
1679 | +++ internal/github.com/mvo5/goconfigparser/README.md 2015-10-30 14:12:15 +0000 |
1680 | @@ -0,0 +1,18 @@ |
1681 | +Config File Parser (INI style) |
1682 | +============================== |
1683 | + |
1684 | +This parser is build as a go equivalent of the Python ConfigParser |
1685 | +module and is aimed for maximum compatibility for both the file format |
1686 | +and the API. This should make it easy to use existing python style |
1687 | +configuration files from go and also ease the porting of existing |
1688 | +python code. |
1689 | + |
1690 | +It implements most of RawConfigParser (i.e. no interpolation) at this |
1691 | +point. |
1692 | + |
1693 | +Current Limitations: |
1694 | +-------------------- |
1695 | + * no interpolation |
1696 | + * no defaults |
1697 | + * no write support |
1698 | + * not all API is provided |
1699 | \ No newline at end of file |
1700 | |
1701 | === added file 'internal/github.com/mvo5/goconfigparser/configparser.go' |
1702 | --- internal/github.com/mvo5/goconfigparser/configparser.go 1970-01-01 00:00:00 +0000 |
1703 | +++ internal/github.com/mvo5/goconfigparser/configparser.go 2015-10-30 14:12:15 +0000 |
1704 | @@ -0,0 +1,181 @@ |
1705 | +// A go implementation in the spirit of the python ConfigParser |
1706 | +package goconfigparser |
1707 | + |
1708 | +import ( |
1709 | + "bufio" |
1710 | + "errors" |
1711 | + "fmt" |
1712 | + "io" |
1713 | + "log" |
1714 | + "os" |
1715 | + "regexp" |
1716 | + "strconv" |
1717 | + "strings" |
1718 | +) |
1719 | + |
1720 | +// see python3 configparser.py |
1721 | +var sectionRE = regexp.MustCompile(`\[(?P<header>[^]]+)\]`) |
1722 | +var optionRE = regexp.MustCompile(`^(?P<option>.*?)\s*(?P<vi>[=|:])\s*(?P<value>.*)$`) |
1723 | + |
1724 | +var booleanStates = map[string]bool{ |
1725 | + "1": true, "yes": true, "true": true, "on": true, |
1726 | + "0": false, "no": false, "false": false, "off": false} |
1727 | + |
1728 | +type NoOptionError struct { |
1729 | + s string |
1730 | +} |
1731 | + |
1732 | +func (e NoOptionError) Error() string { |
1733 | + return e.s |
1734 | +} |
1735 | +func newNoOptionError(section, option string) *NoOptionError { |
1736 | + return &NoOptionError{s: fmt.Sprintf("No option %s in section %s", option, section)} |
1737 | +} |
1738 | + |
1739 | +type NoSectionError struct { |
1740 | + s string |
1741 | +} |
1742 | + |
1743 | +func (e NoSectionError) Error() string { |
1744 | + return e.s |
1745 | +} |
1746 | +func newNoSectionError(section string) *NoSectionError { |
1747 | + return &NoSectionError{s: fmt.Sprintf("No section: %s", section)} |
1748 | +} |
1749 | + |
1750 | +type ConfigParser struct { |
1751 | + sections map[string]Section |
1752 | + |
1753 | + // allow data with no ["section"] header via Get("", key) |
1754 | + AllowNoSectionHeader bool |
1755 | +} |
1756 | + |
1757 | +type Section struct { |
1758 | + options map[string]string |
1759 | +} |
1760 | + |
1761 | +// Create a new empty ConfigParser |
1762 | +func New() (cfg *ConfigParser) { |
1763 | + return &ConfigParser{ |
1764 | + sections: make(map[string]Section)} |
1765 | +} |
1766 | + |
1767 | +// Return a string slice of the sections available |
1768 | +func (c *ConfigParser) Sections() (res []string) { |
1769 | + for k, _ := range c.sections { |
1770 | + res = append(res, k) |
1771 | + } |
1772 | + return res |
1773 | +} |
1774 | + |
1775 | +// Return a string slice of the options available in the given section |
1776 | +func (c *ConfigParser) Options(section string) (res []string, err error) { |
1777 | + sect, ok := c.sections[section] |
1778 | + if !ok { |
1779 | + return res, newNoSectionError(section) |
1780 | + } |
1781 | + for k, _ := range sect.options { |
1782 | + res = append(res, k) |
1783 | + } |
1784 | + return res, err |
1785 | +} |
1786 | + |
1787 | +// Attempt to parse the given string as a configuration |
1788 | +// It may return a error if the parsing fails |
1789 | +func (c *ConfigParser) ReadString(s string) (err error) { |
1790 | + r := strings.NewReader(s) |
1791 | + return c.Read(r) |
1792 | +} |
1793 | + |
1794 | +// Attempt to parse the given file as a configuration |
1795 | +// It may return a error if the parsing fails |
1796 | +func (c *ConfigParser) ReadFile(path string) (err error) { |
1797 | + f, err := os.Open(path) |
1798 | + if err != nil { |
1799 | + return err |
1800 | + } |
1801 | + return c.Read(f) |
1802 | +} |
1803 | + |
1804 | +// Attempt to parse the given io.Reader as a configuration |
1805 | +// It may return a error if the reading fails |
1806 | +func (c *ConfigParser) Read(r io.Reader) (err error) { |
1807 | + scanner := bufio.NewScanner(r) |
1808 | + |
1809 | + curSect := "" |
1810 | + // we allow files with no [section] header in this mode, by |
1811 | + // default its a error to be alinged with what python configparser |
1812 | + // is doing |
1813 | + if c.AllowNoSectionHeader { |
1814 | + c.sections[""] = Section{ |
1815 | + options: make(map[string]string)} |
1816 | + } |
1817 | + for scanner.Scan() { |
1818 | + line := scanner.Text() |
1819 | + if sectionRE.MatchString(line) { |
1820 | + matches := sectionRE.FindStringSubmatch(line) |
1821 | + curSect = matches[1] |
1822 | + c.sections[curSect] = Section{ |
1823 | + options: make(map[string]string)} |
1824 | + } else if optionRE.MatchString(line) { |
1825 | + matches := optionRE.FindStringSubmatch(line) |
1826 | + key := matches[1] |
1827 | + value := matches[3] |
1828 | + if _, ok := c.sections[curSect]; !ok { |
1829 | + return newNoSectionError(curSect) |
1830 | + } |
1831 | + c.sections[curSect].options[key] = value |
1832 | + } |
1833 | + } |
1834 | + if err := scanner.Err(); err != nil { |
1835 | + log.Printf("ConfigParser scan error %s from %s", err, r) |
1836 | + } |
1837 | + return err |
1838 | +} |
1839 | + |
1840 | +// Return the option for the given section as string or an error |
1841 | +func (c *ConfigParser) Get(section, option string) (val string, err error) { |
1842 | + if _, ok := c.sections[section]; !ok { |
1843 | + return val, newNoSectionError(section) |
1844 | + } |
1845 | + sec := c.sections[section] |
1846 | + |
1847 | + if _, ok := sec.options[option]; !ok { |
1848 | + return val, newNoOptionError(section, option) |
1849 | + } |
1850 | + |
1851 | + return sec.options[option], err |
1852 | +} |
1853 | + |
1854 | +// Return the option for the given section as integer or an error |
1855 | +func (c *ConfigParser) Getint(section, option string) (val int, err error) { |
1856 | + sv, err := c.Get(section, option) |
1857 | + if err != nil { |
1858 | + return val, err |
1859 | + } |
1860 | + return strconv.Atoi(sv) |
1861 | +} |
1862 | + |
1863 | +// Return the option for the given section as float or an error |
1864 | +func (c *ConfigParser) Getfloat(section, option string) (val float64, err error) { |
1865 | + sv, err := c.Get(section, option) |
1866 | + if err != nil { |
1867 | + return val, err |
1868 | + } |
1869 | + return strconv.ParseFloat(sv, 64) |
1870 | +} |
1871 | + |
1872 | +// Return the option for the given section as boolean or an error |
1873 | +func (c *ConfigParser) Getbool(section, option string) (val bool, err error) { |
1874 | + sv, err := c.Get(section, option) |
1875 | + if err != nil { |
1876 | + return val, err |
1877 | + } |
1878 | + |
1879 | + val, ok := booleanStates[strings.ToLower(sv)] |
1880 | + if !ok { |
1881 | + return val, errors.New(fmt.Sprintf("No boolean: %s", sv)) |
1882 | + } |
1883 | + |
1884 | + return val, err |
1885 | +} |
1886 | |
1887 | === added file 'internal/github.com/mvo5/goconfigparser/configparser_test.go' |
1888 | --- internal/github.com/mvo5/goconfigparser/configparser_test.go 1970-01-01 00:00:00 +0000 |
1889 | +++ internal/github.com/mvo5/goconfigparser/configparser_test.go 2015-10-30 14:12:15 +0000 |
1890 | @@ -0,0 +1,127 @@ |
1891 | +package goconfigparser |
1892 | + |
1893 | +import ( |
1894 | + "io/ioutil" |
1895 | + "sort" |
1896 | + "strings" |
1897 | + "testing" |
1898 | + |
1899 | + . "launchpad.net/crackly/internal/launchpad.net/gocheck" |
1900 | +) |
1901 | + |
1902 | +// Hook up gocheck into the "go test" runner |
1903 | +func Test(t *testing.T) { TestingT(t) } |
1904 | + |
1905 | +// partition specific testsuite |
1906 | +type ConfigParserTestSuite struct { |
1907 | + cfg *ConfigParser |
1908 | +} |
1909 | + |
1910 | +var _ = Suite(&ConfigParserTestSuite{}) |
1911 | + |
1912 | +const SAMPLE_INI = ` |
1913 | +[service] |
1914 | +base: system-image.ubuntu.com |
1915 | +http_port: 80 |
1916 | +https_port: 443 |
1917 | +channel: ubuntu-core/devel-proposed |
1918 | +device: generic_amd64 |
1919 | +build_number: 246 |
1920 | +version_detail: ubuntu=20150121,raw-device=20150121,version=246 |
1921 | + |
1922 | +[foo] |
1923 | +bar: baz |
1924 | +yesbool: On |
1925 | +nobool: off |
1926 | +float: 3.14 |
1927 | + |
1928 | +[testOptions] |
1929 | +One: 1 |
1930 | +Two: 2 |
1931 | +` |
1932 | + |
1933 | +func (s *ConfigParserTestSuite) SetUpTest(c *C) { |
1934 | + s.cfg = New() |
1935 | + c.Assert(s.cfg, NotNil) |
1936 | + err := s.cfg.ReadString(SAMPLE_INI) |
1937 | + c.Assert(err, IsNil) |
1938 | +} |
1939 | + |
1940 | +func (s *ConfigParserTestSuite) TestSection(c *C) { |
1941 | + sections := s.cfg.Sections() |
1942 | + sort.Strings(sections) |
1943 | + c.Assert(sections, DeepEquals, []string{"foo", "service", "testOptions"}) |
1944 | +} |
1945 | + |
1946 | +func (s *ConfigParserTestSuite) TestOptions(c *C) { |
1947 | + options, err := s.cfg.Options("testOptions") |
1948 | + c.Assert(err, IsNil) |
1949 | + sort.Strings(options) |
1950 | + c.Assert(options, DeepEquals, []string{"One", "Two"}) |
1951 | +} |
1952 | + |
1953 | +func (s *ConfigParserTestSuite) TestGet(c *C) { |
1954 | + val, err := s.cfg.Get("service", "base") |
1955 | + c.Assert(err, IsNil) |
1956 | + c.Assert(val, Equals, "system-image.ubuntu.com") |
1957 | +} |
1958 | + |
1959 | +func (s *ConfigParserTestSuite) TestGetint(c *C) { |
1960 | + intval, err := s.cfg.Getint("service", "http_port") |
1961 | + c.Assert(err, IsNil) |
1962 | + c.Assert(intval, Equals, 80) |
1963 | +} |
1964 | + |
1965 | +func (s *ConfigParserTestSuite) TestGetfloat(c *C) { |
1966 | + intval, err := s.cfg.Getfloat("foo", "float") |
1967 | + c.Assert(err, IsNil) |
1968 | + c.Assert(intval, Equals, 3.14) |
1969 | +} |
1970 | + |
1971 | +func (s *ConfigParserTestSuite) TestGetbool(c *C) { |
1972 | + boolval, err := s.cfg.Getbool("foo", "yesbool") |
1973 | + c.Assert(err, IsNil) |
1974 | + c.Assert(boolval, Equals, true) |
1975 | + |
1976 | + boolval, err = s.cfg.Getbool("foo", "nobool") |
1977 | + c.Assert(err, IsNil) |
1978 | + c.Assert(boolval, Equals, false) |
1979 | + |
1980 | + boolval, err = s.cfg.Getbool("foo", "bar") |
1981 | + c.Assert(err.Error(), Equals, "No boolean: baz") |
1982 | +} |
1983 | + |
1984 | +func (s *ConfigParserTestSuite) TestErrors(c *C) { |
1985 | + val, err := s.cfg.Get("foo", "bar") |
1986 | + c.Assert(err, IsNil) |
1987 | + c.Assert(val, Equals, "baz") |
1988 | + |
1989 | + val, err = s.cfg.Get("foo", "no-such-option") |
1990 | + c.Assert(err, NotNil) |
1991 | + c.Assert(err.Error(), Equals, "No option no-such-option in section foo") |
1992 | + |
1993 | + val, err = s.cfg.Get("no-such-section", "no-such-value") |
1994 | + c.Assert(err, NotNil) |
1995 | + c.Assert(err.Error(), Equals, "No section: no-such-section") |
1996 | +} |
1997 | + |
1998 | +func (s *ConfigParserTestSuite) TestAllowNoSection(c *C) { |
1999 | + s.cfg = New() |
2000 | + s.cfg.AllowNoSectionHeader = true |
2001 | + err := s.cfg.Read(strings.NewReader(`foo=bar`)) |
2002 | + c.Assert(err, IsNil) |
2003 | + val, err := s.cfg.Get("", "foo") |
2004 | + c.Assert(val, Equals, "bar") |
2005 | +} |
2006 | + |
2007 | +func (s *ConfigParserTestSuite) TestReadFile(c *C) { |
2008 | + tmp, err := ioutil.TempFile("", "") |
2009 | + c.Assert(err, IsNil) |
2010 | + tmp.Write([]byte(SAMPLE_INI)) |
2011 | + |
2012 | + s.cfg = New() |
2013 | + err = s.cfg.ReadFile(tmp.Name()) |
2014 | + c.Assert(err, IsNil) |
2015 | + val, err := s.cfg.Get("foo", "bar") |
2016 | + c.Assert(val, Equals, "baz") |
2017 | +} |
2018 | |
2019 | === added directory 'internal/github.com/mvo5/uboot-go' |
2020 | === added directory 'internal/github.com/mvo5/uboot-go/uenv' |
2021 | === added file 'internal/github.com/mvo5/uboot-go/uenv/env.go' |
2022 | --- internal/github.com/mvo5/uboot-go/uenv/env.go 1970-01-01 00:00:00 +0000 |
2023 | +++ internal/github.com/mvo5/uboot-go/uenv/env.go 2015-10-30 14:12:15 +0000 |
2024 | @@ -0,0 +1,235 @@ |
2025 | +package uenv |
2026 | + |
2027 | +import ( |
2028 | + "bufio" |
2029 | + "bytes" |
2030 | + "encoding/binary" |
2031 | + "fmt" |
2032 | + "hash/crc32" |
2033 | + "io" |
2034 | + "io/ioutil" |
2035 | + "os" |
2036 | + "sort" |
2037 | + "strings" |
2038 | +) |
2039 | + |
2040 | +// FIXME: add config option for that so that the user can select if |
2041 | +// he/she wants env with or without flags |
2042 | +var headerSize = 5 |
2043 | + |
2044 | +// Env contains the data of the uboot environment |
2045 | +type Env struct { |
2046 | + fname string |
2047 | + size int |
2048 | + data map[string]string |
2049 | +} |
2050 | + |
2051 | +// little endian helpers |
2052 | +func readUint32(data []byte) uint32 { |
2053 | + var ret uint32 |
2054 | + buf := bytes.NewBuffer(data) |
2055 | + binary.Read(buf, binary.LittleEndian, &ret) |
2056 | + return ret |
2057 | +} |
2058 | + |
2059 | +func writeUint32(u uint32) []byte { |
2060 | + buf := bytes.NewBuffer(nil) |
2061 | + binary.Write(buf, binary.LittleEndian, &u) |
2062 | + return buf.Bytes() |
2063 | +} |
2064 | + |
2065 | +// Create a new empty uboot env file with the given size |
2066 | +func Create(fname string, size int) (*Env, error) { |
2067 | + f, err := os.Create(fname) |
2068 | + if err != nil { |
2069 | + return nil, err |
2070 | + } |
2071 | + defer f.Close() |
2072 | + |
2073 | + env := &Env{ |
2074 | + fname: fname, |
2075 | + size: size, |
2076 | + data: make(map[string]string), |
2077 | + } |
2078 | + |
2079 | + return env, nil |
2080 | +} |
2081 | + |
2082 | +// Open opens a existing uboot env file |
2083 | +func Open(fname string) (*Env, error) { |
2084 | + f, err := os.Open(fname) |
2085 | + if err != nil { |
2086 | + return nil, err |
2087 | + } |
2088 | + defer f.Close() |
2089 | + |
2090 | + contentWithHeader, err := ioutil.ReadAll(f) |
2091 | + if err != nil { |
2092 | + return nil, err |
2093 | + } |
2094 | + crc := readUint32(contentWithHeader) |
2095 | + |
2096 | + payload := contentWithHeader[headerSize:] |
2097 | + actualCRC := crc32.ChecksumIEEE(payload) |
2098 | + if crc != actualCRC { |
2099 | + return nil, fmt.Errorf("bad CRC: %v != %v", crc, actualCRC) |
2100 | + } |
2101 | + eof := bytes.Index(payload, []byte{0, 0}) |
2102 | + |
2103 | + env := &Env{ |
2104 | + fname: fname, |
2105 | + size: len(contentWithHeader), |
2106 | + data: parseData(payload[:eof]), |
2107 | + } |
2108 | + |
2109 | + return env, nil |
2110 | +} |
2111 | + |
2112 | +func parseData(data []byte) map[string]string { |
2113 | + out := make(map[string]string) |
2114 | + |
2115 | + for _, envStr := range bytes.Split(data, []byte{0}) { |
2116 | + if len(envStr) == 0 || envStr[0] == 0 || envStr[0] == 255 { |
2117 | + continue |
2118 | + } |
2119 | + l := strings.SplitN(string(envStr), "=", 2) |
2120 | + if len(l) == 1 { |
2121 | + panic(fmt.Sprintf("invalid line %q (corrupted file?)", envStr)) |
2122 | + } |
2123 | + key := l[0] |
2124 | + value := l[1] |
2125 | + out[key] = value |
2126 | + } |
2127 | + |
2128 | + return out |
2129 | +} |
2130 | + |
2131 | +func (env *Env) String() string { |
2132 | + out := "" |
2133 | + |
2134 | + env.iterEnv(func(key, value string) { |
2135 | + out += fmt.Sprintf("%s=%s\n", key, value) |
2136 | + }) |
2137 | + |
2138 | + return out |
2139 | +} |
2140 | + |
2141 | +// Get the value of the environment variable |
2142 | +func (env *Env) Get(name string) string { |
2143 | + return env.data[name] |
2144 | +} |
2145 | + |
2146 | +// Set an environment name to the given value, if the value is empty |
2147 | +// the variable will be removed from the environment |
2148 | +func (env *Env) Set(name, value string) { |
2149 | + if name == "" { |
2150 | + panic(fmt.Sprintf("Set() can not be called with empty key for value: %q", value)) |
2151 | + } |
2152 | + if value == "" { |
2153 | + delete(env.data, name) |
2154 | + return |
2155 | + } |
2156 | + env.data[name] = value |
2157 | +} |
2158 | + |
2159 | +// iterEnv calls the passed function f with key, value for environment |
2160 | +// vars. The order is guaranteed (unlike just iterating over the map) |
2161 | +func (env *Env) iterEnv(f func(key, value string)) { |
2162 | + keys := make([]string, 0, len(env.data)) |
2163 | + for k := range env.data { |
2164 | + keys = append(keys, k) |
2165 | + } |
2166 | + sort.Strings(keys) |
2167 | + |
2168 | + for _, k := range keys { |
2169 | + if k == "" { |
2170 | + panic("iterEnv iterating over a empty key") |
2171 | + } |
2172 | + |
2173 | + f(k, env.data[k]) |
2174 | + } |
2175 | +} |
2176 | + |
2177 | +// Save will write out the environment data |
2178 | +func (env *Env) Save() error { |
2179 | + w := bytes.NewBuffer(nil) |
2180 | + // will panic if the buffer can't grow, all writes to |
2181 | + // the buffer will be ok because we sized it correctly |
2182 | + w.Grow(env.size - headerSize) |
2183 | + |
2184 | + // write the payload |
2185 | + env.iterEnv(func(key, value string) { |
2186 | + w.Write([]byte(fmt.Sprintf("%s=%s", key, value))) |
2187 | + w.Write([]byte{0}) |
2188 | + }) |
2189 | + |
2190 | + // write double \0 to mark the end of the env |
2191 | + w.Write([]byte{0}) |
2192 | + |
2193 | + // no keys, so no previous \0 was written so we write one here |
2194 | + if len(env.data) == 0 { |
2195 | + w.Write([]byte{0}) |
2196 | + } |
2197 | + |
2198 | + // write ff into the remaining parts |
2199 | + writtenSoFar := w.Len() |
2200 | + for i := 0; i < env.size-headerSize-writtenSoFar; i++ { |
2201 | + w.Write([]byte{0xff}) |
2202 | + } |
2203 | + |
2204 | + // checksum |
2205 | + crc := crc32.ChecksumIEEE(w.Bytes()) |
2206 | + |
2207 | + // Note that we overwrite the existing file and do not do |
2208 | + // the usual write-rename. The rationale is that we want to |
2209 | + // minimize the amount of writes happening on a potential |
2210 | + // FAT partition where the env is loaded from. The file will |
2211 | + // always be of a fixed size so we know the writes will not |
2212 | + // fail because of ENOSPC. |
2213 | + // |
2214 | + // The size of the env file never changes so we do not |
2215 | + // truncate it. |
2216 | + // |
2217 | + // We also do not O_TRUNC to avoid reallocations on the FS |
2218 | + // to minimize risk of fs corruption. |
2219 | + f, err := os.OpenFile(env.fname, os.O_WRONLY, 0666) |
2220 | + if err != nil { |
2221 | + return err |
2222 | + } |
2223 | + defer f.Close() |
2224 | + |
2225 | + if _, err := f.Write(writeUint32(crc)); err != nil { |
2226 | + return err |
2227 | + } |
2228 | + // padding bytes (e.g. for redundant header) |
2229 | + pad := make([]byte, headerSize-binary.Size(crc)) |
2230 | + if _, err := f.Write(pad); err != nil { |
2231 | + return err |
2232 | + } |
2233 | + if _, err := f.Write(w.Bytes()); err != nil { |
2234 | + return err |
2235 | + } |
2236 | + |
2237 | + return f.Sync() |
2238 | +} |
2239 | + |
2240 | +// Import is a helper that imports a given text file that contains |
2241 | +// "key=value" paris into the uboot env. Lines starting with ^# are |
2242 | +// ignored (like the input file on mkenvimage) |
2243 | +func (env *Env) Import(r io.Reader) error { |
2244 | + scanner := bufio.NewScanner(r) |
2245 | + for scanner.Scan() { |
2246 | + line := scanner.Text() |
2247 | + if strings.HasPrefix(line, "#") || len(line) == 0 { |
2248 | + continue |
2249 | + } |
2250 | + l := strings.SplitN(line, "=", 2) |
2251 | + if len(l) == 1 { |
2252 | + return fmt.Errorf("Invalid line: %q", line) |
2253 | + } |
2254 | + env.data[l[0]] = l[1] |
2255 | + |
2256 | + } |
2257 | + |
2258 | + return scanner.Err() |
2259 | +} |
2260 | |
2261 | === added file 'internal/github.com/mvo5/uboot-go/uenv/env_test.go' |
2262 | --- internal/github.com/mvo5/uboot-go/uenv/env_test.go 1970-01-01 00:00:00 +0000 |
2263 | +++ internal/github.com/mvo5/uboot-go/uenv/env_test.go 2015-10-30 14:12:15 +0000 |
2264 | @@ -0,0 +1,203 @@ |
2265 | +package uenv |
2266 | + |
2267 | +import ( |
2268 | + "bytes" |
2269 | + "hash/crc32" |
2270 | + "io/ioutil" |
2271 | + "os" |
2272 | + "path/filepath" |
2273 | + "strings" |
2274 | + "testing" |
2275 | + |
2276 | + . "launchpad.net/crackly/internal/gopkg.in/check.v1" |
2277 | +) |
2278 | + |
2279 | +// Hook up check.v1 into the "go test" runner |
2280 | +func Test(t *testing.T) { TestingT(t) } |
2281 | + |
2282 | +type uenvTestSuite struct { |
2283 | + envFile string |
2284 | +} |
2285 | + |
2286 | +var _ = Suite(&uenvTestSuite{}) |
2287 | + |
2288 | +func (u *uenvTestSuite) SetUpTest(c *C) { |
2289 | + u.envFile = filepath.Join(c.MkDir(), "uboot.env") |
2290 | +} |
2291 | + |
2292 | +func (u *uenvTestSuite) TestSetNoDuplicate(c *C) { |
2293 | + env, err := Create(u.envFile, 4096) |
2294 | + c.Assert(err, IsNil) |
2295 | + env.Set("foo", "bar") |
2296 | + env.Set("foo", "bar") |
2297 | + c.Assert(env.String(), Equals, "foo=bar\n") |
2298 | +} |
2299 | + |
2300 | +func (u *uenvTestSuite) TestOpenEnv(c *C) { |
2301 | + env, err := Create(u.envFile, 4096) |
2302 | + c.Assert(err, IsNil) |
2303 | + env.Set("foo", "bar") |
2304 | + c.Assert(env.String(), Equals, "foo=bar\n") |
2305 | + err = env.Save() |
2306 | + c.Assert(err, IsNil) |
2307 | + |
2308 | + env2, err := Open(u.envFile) |
2309 | + c.Assert(err, IsNil) |
2310 | + c.Assert(env2.String(), Equals, "foo=bar\n") |
2311 | +} |
2312 | + |
2313 | +func (u *uenvTestSuite) TestGetSimple(c *C) { |
2314 | + env, err := Create(u.envFile, 4096) |
2315 | + c.Assert(err, IsNil) |
2316 | + env.Set("foo", "bar") |
2317 | + c.Assert(env.Get("foo"), Equals, "bar") |
2318 | +} |
2319 | + |
2320 | +func (u *uenvTestSuite) TestGetNoSuchEntry(c *C) { |
2321 | + env, err := Create(u.envFile, 4096) |
2322 | + c.Assert(err, IsNil) |
2323 | + c.Assert(env.Get("no-such-entry"), Equals, "") |
2324 | +} |
2325 | + |
2326 | +func (u *uenvTestSuite) TestImport(c *C) { |
2327 | + env, err := Create(u.envFile, 4096) |
2328 | + c.Assert(err, IsNil) |
2329 | + |
2330 | + r := strings.NewReader("foo=bar\n#comment\n\nbaz=baz") |
2331 | + err = env.Import(r) |
2332 | + c.Assert(err, IsNil) |
2333 | + // order is alphabetic |
2334 | + c.Assert(env.String(), Equals, "baz=baz\nfoo=bar\n") |
2335 | +} |
2336 | + |
2337 | +func (u *uenvTestSuite) TestImportHasError(c *C) { |
2338 | + env, err := Create(u.envFile, 4096) |
2339 | + c.Assert(err, IsNil) |
2340 | + |
2341 | + r := strings.NewReader("foxy") |
2342 | + err = env.Import(r) |
2343 | + c.Assert(err, ErrorMatches, "Invalid line: \"foxy\"") |
2344 | +} |
2345 | + |
2346 | +func (u *uenvTestSuite) TestSetEmptyUnsets(c *C) { |
2347 | + env, err := Create(u.envFile, 4096) |
2348 | + c.Assert(err, IsNil) |
2349 | + |
2350 | + env.Set("foo", "bar") |
2351 | + c.Assert(env.String(), Equals, "foo=bar\n") |
2352 | + env.Set("foo", "") |
2353 | + c.Assert(env.String(), Equals, "") |
2354 | +} |
2355 | + |
2356 | +func (u *uenvTestSuite) makeUbootEnvFromData(c *C, mockData []byte) { |
2357 | + w := bytes.NewBuffer(nil) |
2358 | + crc := crc32.ChecksumIEEE(mockData) |
2359 | + w.Write(writeUint32(crc)) |
2360 | + w.Write([]byte{0}) |
2361 | + w.Write(mockData) |
2362 | + |
2363 | + f, err := os.Create(u.envFile) |
2364 | + c.Assert(err, IsNil) |
2365 | + defer f.Close() |
2366 | + _, err = f.Write(w.Bytes()) |
2367 | + c.Assert(err, IsNil) |
2368 | +} |
2369 | + |
2370 | +// ensure that the data after \0\0 is discarded (except for crc) |
2371 | +func (u *uenvTestSuite) TestReadStopsAfterDoubleNull(c *C) { |
2372 | + mockData := []byte{ |
2373 | + // foo=bar |
2374 | + 0x66, 0x6f, 0x6f, 0x3d, 0x62, 0x61, 0x72, |
2375 | + // eof |
2376 | + 0x00, 0x00, |
2377 | + // junk after eof as written by fw_setenv sometimes |
2378 | + // =b |
2379 | + 0x3d, 62, |
2380 | + // empty |
2381 | + 0xff, 0xff, |
2382 | + } |
2383 | + u.makeUbootEnvFromData(c, mockData) |
2384 | + |
2385 | + env, err := Open(u.envFile) |
2386 | + c.Assert(err, IsNil) |
2387 | + c.Assert(env.String(), Equals, "foo=bar\n") |
2388 | +} |
2389 | + |
2390 | +func (u *uenvTestSuite) TestReadEmptyFile(c *C) { |
2391 | + mockData := []byte{ |
2392 | + // eof |
2393 | + 0x00, 0x00, |
2394 | + // empty |
2395 | + 0xff, 0xff, |
2396 | + } |
2397 | + u.makeUbootEnvFromData(c, mockData) |
2398 | + |
2399 | + env, err := Open(u.envFile) |
2400 | + c.Assert(err, IsNil) |
2401 | + c.Assert(env.String(), Equals, "") |
2402 | +} |
2403 | + |
2404 | +func (u *uenvTestSuite) TestWritesEmptyFileWithDoubleNewline(c *C) { |
2405 | + env, err := Create(u.envFile, 12) |
2406 | + c.Assert(err, IsNil) |
2407 | + err = env.Save() |
2408 | + c.Assert(err, IsNil) |
2409 | + |
2410 | + r, err := os.Open(u.envFile) |
2411 | + c.Assert(err, IsNil) |
2412 | + defer r.Close() |
2413 | + content, err := ioutil.ReadAll(r) |
2414 | + c.Assert(err, IsNil) |
2415 | + c.Assert(content, DeepEquals, []byte{ |
2416 | + // crc |
2417 | + 0x11, 0x38, 0xb3, 0x89, |
2418 | + // redundant |
2419 | + 0x0, |
2420 | + // eof |
2421 | + 0x0, 0x0, |
2422 | + // footer |
2423 | + 0xff, 0xff, 0xff, 0xff, 0xff, |
2424 | + }) |
2425 | + |
2426 | + env, err = Open(u.envFile) |
2427 | + c.Assert(err, IsNil) |
2428 | + c.Assert(env.String(), Equals, "") |
2429 | +} |
2430 | + |
2431 | +func (u *uenvTestSuite) TestWritesContentCorrectly(c *C) { |
2432 | + totalSize := 16 |
2433 | + |
2434 | + env, err := Create(u.envFile, totalSize) |
2435 | + c.Assert(err, IsNil) |
2436 | + env.Set("a", "b") |
2437 | + env.Set("c", "d") |
2438 | + err = env.Save() |
2439 | + c.Assert(err, IsNil) |
2440 | + |
2441 | + r, err := os.Open(u.envFile) |
2442 | + c.Assert(err, IsNil) |
2443 | + defer r.Close() |
2444 | + content, err := ioutil.ReadAll(r) |
2445 | + c.Assert(err, IsNil) |
2446 | + c.Assert(content, DeepEquals, []byte{ |
2447 | + // crc |
2448 | + 0xc7, 0xd9, 0x6b, 0xc5, |
2449 | + // redundant |
2450 | + 0x0, |
2451 | + // a=b |
2452 | + 0x61, 0x3d, 0x62, |
2453 | + // eol |
2454 | + 0x0, |
2455 | + // c=d |
2456 | + 0x63, 0x3d, 0x64, |
2457 | + // eof |
2458 | + 0x0, 0x0, |
2459 | + // footer |
2460 | + 0xff, 0xff, |
2461 | + }) |
2462 | + |
2463 | + env, err = Open(u.envFile) |
2464 | + c.Assert(err, IsNil) |
2465 | + c.Assert(env.String(), Equals, "a=b\nc=d\n") |
2466 | + c.Assert(env.size, Equals, totalSize) |
2467 | +} |
2468 | |
2469 | === added directory 'internal/github.com/olekukonko' |
2470 | === added directory 'internal/github.com/olekukonko/ts' |
2471 | === added file 'internal/github.com/olekukonko/ts/LICENCE' |
2472 | --- internal/github.com/olekukonko/ts/LICENCE 1970-01-01 00:00:00 +0000 |
2473 | +++ internal/github.com/olekukonko/ts/LICENCE 2015-10-30 14:12:15 +0000 |
2474 | @@ -0,0 +1,19 @@ |
2475 | +Copyright (C) 2014 by Oleku Konko |
2476 | + |
2477 | +Permission is hereby granted, free of charge, to any person obtaining a copy |
2478 | +of this software and associated documentation files (the "Software"), to deal |
2479 | +in the Software without restriction, including without limitation the rights |
2480 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
2481 | +copies of the Software, and to permit persons to whom the Software is |
2482 | +furnished to do so, subject to the following conditions: |
2483 | + |
2484 | +The above copyright notice and this permission notice shall be included in |
2485 | +all copies or substantial portions of the Software. |
2486 | + |
2487 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
2488 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
2489 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
2490 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
2491 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
2492 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
2493 | +THE SOFTWARE. |
2494 | \ No newline at end of file |
2495 | |
2496 | === added file 'internal/github.com/olekukonko/ts/README.md' |
2497 | --- internal/github.com/olekukonko/ts/README.md 1970-01-01 00:00:00 +0000 |
2498 | +++ internal/github.com/olekukonko/ts/README.md 2015-10-30 14:12:15 +0000 |
2499 | @@ -0,0 +1,28 @@ |
2500 | +ts (Terminal Size) |
2501 | +== |
2502 | + |
2503 | +[![Build Status](https://travis-ci.org/olekukonko/ts.png?branch=master)](https://travis-ci.org/olekukonko/ts) [![Total views](https://sourcegraph.com/api/repos/github.com/olekukonko/ts/counters/views.png)](https://sourcegraph.com/github.com/olekukonko/ts) |
2504 | + |
2505 | +Simple go Application to get Terminal Size. So Many Implementations do not support windows but `ts` has full windows support. |
2506 | +Run `go get github.com/olekukonko/ts` to download and install |
2507 | + |
2508 | +#### Example |
2509 | + |
2510 | +```go |
2511 | +package main |
2512 | + |
2513 | +import ( |
2514 | + "fmt" |
2515 | + "github.com/olekukonko/ts" |
2516 | +) |
2517 | + |
2518 | +func main() { |
2519 | + size, _ := ts.GetSize() |
2520 | + fmt.Println(size.Col()) // Get Width |
2521 | + fmt.Println(size.Row()) // Get Height |
2522 | + fmt.Println(size.PosX()) // Get X position |
2523 | + fmt.Println(size.PosY()) // Get Y position |
2524 | +} |
2525 | +``` |
2526 | + |
2527 | +[See Documentation](http://godoc.org/github.com/olekukonko/ts) |
2528 | |
2529 | === added file 'internal/github.com/olekukonko/ts/doc.go' |
2530 | --- internal/github.com/olekukonko/ts/doc.go 1970-01-01 00:00:00 +0000 |
2531 | +++ internal/github.com/olekukonko/ts/doc.go 2015-10-30 14:12:15 +0000 |
2532 | @@ -0,0 +1,36 @@ |
2533 | +// Copyright 2014 Oleku Konko All rights reserved. |
2534 | +// Use of this source code is governed by a MIT |
2535 | +// license that can be found in the LICENSE file. |
2536 | + |
2537 | +// This module is a Terminal API for the Go Programming Language. |
2538 | +// The protocols were written in pure Go and works on windows and unix systems |
2539 | + |
2540 | +/** |
2541 | + |
2542 | +Simple go Application to get Terminal Size. So Many Implementations do not support windows but `ts` has full windows support. |
2543 | +Run `go get github.com/olekukonko/ts` to download and install |
2544 | + |
2545 | +Installation |
2546 | + |
2547 | +Minimum requirements are Go 1.1+ with fill Windows support |
2548 | + |
2549 | +Example |
2550 | + |
2551 | + package main |
2552 | + |
2553 | + import ( |
2554 | + "fmt" |
2555 | + "github.com/olekukonko/ts" |
2556 | + ) |
2557 | + |
2558 | + func main() { |
2559 | + size, _ := ts.GetSize() |
2560 | + fmt.Println(size.Col()) // Get Width |
2561 | + fmt.Println(size.Row()) // Get Height |
2562 | + fmt.Println(size.PosX()) // Get X position |
2563 | + fmt.Println(size.PosY()) // Get Y position |
2564 | + } |
2565 | + |
2566 | +**/ |
2567 | + |
2568 | +package ts |
2569 | |
2570 | === added file 'internal/github.com/olekukonko/ts/ts.go' |
2571 | --- internal/github.com/olekukonko/ts/ts.go 1970-01-01 00:00:00 +0000 |
2572 | +++ internal/github.com/olekukonko/ts/ts.go 2015-10-30 14:12:15 +0000 |
2573 | @@ -0,0 +1,36 @@ |
2574 | +// Copyright 2014 Oleku Konko All rights reserved. |
2575 | +// Use of this source code is governed by a MIT |
2576 | +// license that can be found in the LICENSE file. |
2577 | + |
2578 | +// This module is a Terminal API for the Go Programming Language. |
2579 | +// The protocols were written in pure Go and works on windows and unix systems |
2580 | + |
2581 | +package ts |
2582 | + |
2583 | +// Return System Size |
2584 | +type Size struct { |
2585 | + row uint16 |
2586 | + col uint16 |
2587 | + posX uint16 |
2588 | + posY uint16 |
2589 | +} |
2590 | + |
2591 | +// Get Terminal Width |
2592 | +func (w Size) Col() int { |
2593 | + return int(w.col) |
2594 | +} |
2595 | + |
2596 | +// Get Terminal Height |
2597 | +func (w Size) Row() int { |
2598 | + return int(w.row) |
2599 | +} |
2600 | + |
2601 | +// Get Position X |
2602 | +func (w Size) PosX() int { |
2603 | + return int(w.posX) |
2604 | +} |
2605 | + |
2606 | +// Get Position Y |
2607 | +func (w Size) PosY() int { |
2608 | + return int(w.posY) |
2609 | +} |
2610 | |
2611 | === added file 'internal/github.com/olekukonko/ts/ts_darwin.go' |
2612 | --- internal/github.com/olekukonko/ts/ts_darwin.go 1970-01-01 00:00:00 +0000 |
2613 | +++ internal/github.com/olekukonko/ts/ts_darwin.go 2015-10-30 14:12:15 +0000 |
2614 | @@ -0,0 +1,14 @@ |
2615 | +// +build darwin |
2616 | + |
2617 | +// Copyright 2014 Oleku Konko All rights reserved. |
2618 | +// Use of this source code is governed by a MIT |
2619 | +// license that can be found in the LICENSE file. |
2620 | + |
2621 | +// This module is a Terminal API for the Go Programming Language. |
2622 | +// The protocols were written in pure Go and works on windows and unix systems |
2623 | + |
2624 | +package ts |
2625 | + |
2626 | +const ( |
2627 | + TIOCGWINSZ = 0x40087468 |
2628 | +) |
2629 | |
2630 | === added file 'internal/github.com/olekukonko/ts/ts_linux.go' |
2631 | --- internal/github.com/olekukonko/ts/ts_linux.go 1970-01-01 00:00:00 +0000 |
2632 | +++ internal/github.com/olekukonko/ts/ts_linux.go 2015-10-30 14:12:15 +0000 |
2633 | @@ -0,0 +1,13 @@ |
2634 | +// +build linux |
2635 | + |
2636 | +// Copyright 2014 Oleku Konko All rights reserved. |
2637 | +// Use of this source code is governed by a MIT |
2638 | +// license that can be found in the LICENSE file. |
2639 | + |
2640 | +// This module is a Terminal API for the Go Programming Language. |
2641 | +// The protocols were written in pure Go and works on windows and unix systems |
2642 | +package ts |
2643 | + |
2644 | +const ( |
2645 | + TIOCGWINSZ = 0x5413 |
2646 | +) |
2647 | |
2648 | === added file 'internal/github.com/olekukonko/ts/ts_other.go' |
2649 | --- internal/github.com/olekukonko/ts/ts_other.go 1970-01-01 00:00:00 +0000 |
2650 | +++ internal/github.com/olekukonko/ts/ts_other.go 2015-10-30 14:12:15 +0000 |
2651 | @@ -0,0 +1,14 @@ |
2652 | +// +build !windows,!darwin,!freebsd,!netbsd,!openbsd,!linux |
2653 | + |
2654 | +// Copyright 2014 Oleku Konko All rights reserved. |
2655 | +// Use of this source code is governed by a MIT |
2656 | +// license that can be found in the LICENSE file. |
2657 | + |
2658 | +// This module is a Terminal API for the Go Programming Language. |
2659 | +// The protocols were written in pure Go and works on windows and unix systems |
2660 | + |
2661 | +package ts |
2662 | + |
2663 | +const ( |
2664 | + TIOCGWINSZ = 0 |
2665 | +) |
2666 | |
2667 | === added file 'internal/github.com/olekukonko/ts/ts_test.go' |
2668 | --- internal/github.com/olekukonko/ts/ts_test.go 1970-01-01 00:00:00 +0000 |
2669 | +++ internal/github.com/olekukonko/ts/ts_test.go 2015-10-30 14:12:15 +0000 |
2670 | @@ -0,0 +1,32 @@ |
2671 | +// Copyright 2014 Oleku Konko All rights reserved. |
2672 | +// Use of this source code is governed by a MIT |
2673 | +// license that can be found in the LICENSE file. |
2674 | + |
2675 | +// This module is a Terminal API for the Go Programming Language. |
2676 | +// The protocols were written in pure Go and works on windows and unix systems |
2677 | + |
2678 | +package ts |
2679 | + |
2680 | +import ( |
2681 | + "fmt" |
2682 | + "testing" |
2683 | +) |
2684 | + |
2685 | +func ExampleGetSize() { |
2686 | + size, _ := GetSize() |
2687 | + fmt.Println(size.Col()) // Get Width |
2688 | + fmt.Println(size.Row()) // Get Height |
2689 | + fmt.Println(size.PosX()) // Get X position |
2690 | + fmt.Println(size.PosY()) // Get Y position |
2691 | +} |
2692 | + |
2693 | +func TestSize(t *testing.T) { |
2694 | + size, err := GetSize() |
2695 | + |
2696 | + if err != nil { |
2697 | + t.Fatal(err) |
2698 | + } |
2699 | + if size.Col() == 0 || size.Row() == 0 { |
2700 | + t.Fatalf("Screen Size Failed") |
2701 | + } |
2702 | +} |
2703 | |
2704 | === added file 'internal/github.com/olekukonko/ts/ts_unix.go' |
2705 | --- internal/github.com/olekukonko/ts/ts_unix.go 1970-01-01 00:00:00 +0000 |
2706 | +++ internal/github.com/olekukonko/ts/ts_unix.go 2015-10-30 14:12:15 +0000 |
2707 | @@ -0,0 +1,14 @@ |
2708 | +// +build freebsd netbsd openbsd |
2709 | + |
2710 | +// Copyright 2014 Oleku Konko All rights reserved. |
2711 | +// Use of this source code is governed by a MIT |
2712 | +// license that can be found in the LICENSE file. |
2713 | + |
2714 | +// This module is a Terminal API for the Go Programming Language. |
2715 | +// The protocols were written in pure Go and works on windows and unix systems |
2716 | + |
2717 | +package ts |
2718 | + |
2719 | +const ( |
2720 | + TIOCGWINSZ = 0x40087468 |
2721 | +) |
2722 | |
2723 | === added file 'internal/github.com/olekukonko/ts/ts_windows.go' |
2724 | --- internal/github.com/olekukonko/ts/ts_windows.go 1970-01-01 00:00:00 +0000 |
2725 | +++ internal/github.com/olekukonko/ts/ts_windows.go 2015-10-30 14:12:15 +0000 |
2726 | @@ -0,0 +1,64 @@ |
2727 | +// +build windows |
2728 | + |
2729 | +// Copyright 2014 Oleku Konko All rights reserved. |
2730 | +// Use of this source code is governed by a MIT |
2731 | +// license that can be found in the LICENSE file. |
2732 | + |
2733 | +// This module is a Terminal API for the Go Programming Language. |
2734 | +// The protocols were written in pure Go and works on windows and unix systems |
2735 | + |
2736 | +package ts |
2737 | + |
2738 | +import ( |
2739 | + "syscall" |
2740 | + "unsafe" |
2741 | +) |
2742 | + |
2743 | +var ( |
2744 | + kernel32 = syscall.NewLazyDLL("kernel32.dll") |
2745 | + |
2746 | + // Retrieves information about the specified console screen buffer. |
2747 | + // See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx |
2748 | + screenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") |
2749 | +) |
2750 | + |
2751 | +// Contains information about a console screen buffer. |
2752 | +// http://msdn.microsoft.com/en-us/library/windows/desktop/ms682093(v=vs.85).aspx |
2753 | +type CONSOLE_SCREEN_BUFFER_INFO struct { |
2754 | + DwSize COORD |
2755 | + DwCursorPosition COORD |
2756 | + WAttributes uint16 |
2757 | + SrWindow SMALL_RECT |
2758 | + DwMaximumWindowSize COORD |
2759 | +} |
2760 | + |
2761 | +// Defines the coordinates of a character cell in a console screen buffer. |
2762 | +// The origin of the coordinate system (0,0) is at the top, left cell of the buffer. |
2763 | +// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682119(v=vs.85).aspx |
2764 | +type COORD struct { |
2765 | + X, Y uint16 |
2766 | +} |
2767 | + |
2768 | +// Defines the coordinates of the upper left and lower right corners of a rectangle. |
2769 | +// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686311(v=vs.85).aspx |
2770 | +type SMALL_RECT struct { |
2771 | + Left, Top, Right, Bottom uint16 |
2772 | +} |
2773 | + |
2774 | +func GetSize() (ws Size, err error) { |
2775 | + var info CONSOLE_SCREEN_BUFFER_INFO |
2776 | + rc, _, err := screenBufferInfo.Call( |
2777 | + uintptr(syscall.Stdout), |
2778 | + uintptr(unsafe.Pointer(&info))) |
2779 | + |
2780 | + if rc == 0 { |
2781 | + return ws, err |
2782 | + } |
2783 | + |
2784 | + ws = Size{info.SrWindow.Bottom, |
2785 | + info.SrWindow.Right, |
2786 | + info.DwCursorPosition.X, |
2787 | + info.DwCursorPosition.Y} |
2788 | + |
2789 | + return ws, nil |
2790 | +} |
2791 | |
2792 | === added file 'internal/github.com/olekukonko/ts/ts_x.go' |
2793 | --- internal/github.com/olekukonko/ts/ts_x.go 1970-01-01 00:00:00 +0000 |
2794 | +++ internal/github.com/olekukonko/ts/ts_x.go 2015-10-30 14:12:15 +0000 |
2795 | @@ -0,0 +1,46 @@ |
2796 | +// +build !windows |
2797 | + |
2798 | +// Copyright 2014 Oleku Konko All rights reserved. |
2799 | +// Use of this source code is governed by a MIT |
2800 | +// license that can be found in the LICENSE file. |
2801 | + |
2802 | +// This module is a Terminal API for the Go Programming Language. |
2803 | +// The protocols were written in pure Go and works on windows and unix systems |
2804 | + |
2805 | +package ts |
2806 | + |
2807 | +import ( |
2808 | + "syscall" |
2809 | + "unsafe" |
2810 | +) |
2811 | + |
2812 | +// Get Windows Size |
2813 | +func GetSize() (ws Size, err error) { |
2814 | + _, _, ec := syscall.Syscall(syscall.SYS_IOCTL, |
2815 | + uintptr(syscall.Stdout), |
2816 | + uintptr(TIOCGWINSZ), |
2817 | + uintptr(unsafe.Pointer(&ws))) |
2818 | + |
2819 | + err = getError(ec) |
2820 | + |
2821 | + if TIOCGWINSZ == 0 && err != nil { |
2822 | + ws = Size{80, 25, 0, 0} |
2823 | + } |
2824 | + return ws, err |
2825 | +} |
2826 | + |
2827 | +func getError(ec interface{}) (err error) { |
2828 | + switch v := ec.(type) { |
2829 | + |
2830 | + case syscall.Errno: // Some implementation return syscall.Errno number |
2831 | + if v != 0 { |
2832 | + err = syscall.Errno(v) |
2833 | + } |
2834 | + |
2835 | + case error: // Some implementation return error |
2836 | + err = ec.(error) |
2837 | + default: |
2838 | + err = nil |
2839 | + } |
2840 | + return |
2841 | +} |
2842 | |
2843 | === added directory 'internal/gopkg.in' |
2844 | === added directory 'internal/gopkg.in/check.v1' |
2845 | === added file 'internal/gopkg.in/check.v1/LICENSE' |
2846 | --- internal/gopkg.in/check.v1/LICENSE 1970-01-01 00:00:00 +0000 |
2847 | +++ internal/gopkg.in/check.v1/LICENSE 2015-10-30 14:12:15 +0000 |
2848 | @@ -0,0 +1,25 @@ |
2849 | +Gocheck - A rich testing framework for Go |
2850 | + |
2851 | +Copyright (c) 2010-2013 Gustavo Niemeyer <gustavo@niemeyer.net> |
2852 | + |
2853 | +All rights reserved. |
2854 | + |
2855 | +Redistribution and use in source and binary forms, with or without |
2856 | +modification, are permitted provided that the following conditions are met: |
2857 | + |
2858 | +1. Redistributions of source code must retain the above copyright notice, this |
2859 | + list of conditions and the following disclaimer. |
2860 | +2. Redistributions in binary form must reproduce the above copyright notice, |
2861 | + this list of conditions and the following disclaimer in the documentation |
2862 | + and/or other materials provided with the distribution. |
2863 | + |
2864 | +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
2865 | +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
2866 | +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
2867 | +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR |
2868 | +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
2869 | +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
2870 | +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
2871 | +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
2872 | +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
2873 | +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
2874 | |
2875 | === added file 'internal/gopkg.in/check.v1/README.md' |
2876 | --- internal/gopkg.in/check.v1/README.md 1970-01-01 00:00:00 +0000 |
2877 | +++ internal/gopkg.in/check.v1/README.md 2015-10-30 14:12:15 +0000 |
2878 | @@ -0,0 +1,20 @@ |
2879 | +Instructions |
2880 | +============ |
2881 | + |
2882 | +Install the package with: |
2883 | + |
2884 | + go get gopkg.in/check.v1 |
2885 | + |
2886 | +Import it with: |
2887 | + |
2888 | + import "gopkg.in/check.v1" |
2889 | + |
2890 | +and use _check_ as the package name inside the code. |
2891 | + |
2892 | +For more details, visit the project page: |
2893 | + |
2894 | +* http://labix.org/gocheck |
2895 | + |
2896 | +and the API documentation: |
2897 | + |
2898 | +* https://gopkg.in/check.v1 |
2899 | |
2900 | === added file 'internal/gopkg.in/check.v1/TODO' |
2901 | --- internal/gopkg.in/check.v1/TODO 1970-01-01 00:00:00 +0000 |
2902 | +++ internal/gopkg.in/check.v1/TODO 2015-10-30 14:12:15 +0000 |
2903 | @@ -0,0 +1,2 @@ |
2904 | +- Assert(slice, Contains, item) |
2905 | +- Parallel test support |
2906 | |
2907 | === added file 'internal/gopkg.in/check.v1/benchmark.go' |
2908 | --- internal/gopkg.in/check.v1/benchmark.go 1970-01-01 00:00:00 +0000 |
2909 | +++ internal/gopkg.in/check.v1/benchmark.go 2015-10-30 14:12:15 +0000 |
2910 | @@ -0,0 +1,163 @@ |
2911 | +// Copyright 2009 The Go Authors. All rights reserved. |
2912 | +// Use of this source code is governed by a BSD-style |
2913 | +// license that can be found in the LICENSE file. |
2914 | + |
2915 | +package check |
2916 | + |
2917 | +import ( |
2918 | + "fmt" |
2919 | + "runtime" |
2920 | + "time" |
2921 | +) |
2922 | + |
2923 | +var memStats runtime.MemStats |
2924 | + |
2925 | +// testingB is a type passed to Benchmark functions to manage benchmark |
2926 | +// timing and to specify the number of iterations to run. |
2927 | +type timer struct { |
2928 | + start time.Time // Time test or benchmark started |
2929 | + duration time.Duration |
2930 | + N int |
2931 | + bytes int64 |
2932 | + timerOn bool |
2933 | + benchTime time.Duration |
2934 | + // The initial states of memStats.Mallocs and memStats.TotalAlloc. |
2935 | + startAllocs uint64 |
2936 | + startBytes uint64 |
2937 | + // The net total of this test after being run. |
2938 | + netAllocs uint64 |
2939 | + netBytes uint64 |
2940 | +} |
2941 | + |
2942 | +// StartTimer starts timing a test. This function is called automatically |
2943 | +// before a benchmark starts, but it can also used to resume timing after |
2944 | +// a call to StopTimer. |
2945 | +func (c *C) StartTimer() { |
2946 | + if !c.timerOn { |
2947 | + c.start = time.Now() |
2948 | + c.timerOn = true |
2949 | + |
2950 | + runtime.ReadMemStats(&memStats) |
2951 | + c.startAllocs = memStats.Mallocs |
2952 | + c.startBytes = memStats.TotalAlloc |
2953 | + } |
2954 | +} |
2955 | + |
2956 | +// StopTimer stops timing a test. This can be used to pause the timer |
2957 | +// while performing complex initialization that you don't |
2958 | +// want to measure. |
2959 | +func (c *C) StopTimer() { |
2960 | + if c.timerOn { |
2961 | + c.duration += time.Now().Sub(c.start) |
2962 | + c.timerOn = false |
2963 | + runtime.ReadMemStats(&memStats) |
2964 | + c.netAllocs += memStats.Mallocs - c.startAllocs |
2965 | + c.netBytes += memStats.TotalAlloc - c.startBytes |
2966 | + } |
2967 | +} |
2968 | + |
2969 | +// ResetTimer sets the elapsed benchmark time to zero. |
2970 | +// It does not affect whether the timer is running. |
2971 | +func (c *C) ResetTimer() { |
2972 | + if c.timerOn { |
2973 | + c.start = time.Now() |
2974 | + runtime.ReadMemStats(&memStats) |
2975 | + c.startAllocs = memStats.Mallocs |
2976 | + c.startBytes = memStats.TotalAlloc |
2977 | + } |
2978 | + c.duration = 0 |
2979 | + c.netAllocs = 0 |
2980 | + c.netBytes = 0 |
2981 | +} |
2982 | + |
2983 | +// SetBytes informs the number of bytes that the benchmark processes |
2984 | +// on each iteration. If this is called in a benchmark it will also |
2985 | +// report MB/s. |
2986 | +func (c *C) SetBytes(n int64) { |
2987 | + c.bytes = n |
2988 | +} |
2989 | + |
2990 | +func (c *C) nsPerOp() int64 { |
2991 | + if c.N <= 0 { |
2992 | + return 0 |
2993 | + } |
2994 | + return c.duration.Nanoseconds() / int64(c.N) |
2995 | +} |
2996 | + |
2997 | +func (c *C) mbPerSec() float64 { |
2998 | + if c.bytes <= 0 || c.duration <= 0 || c.N <= 0 { |
2999 | + return 0 |
3000 | + } |
3001 | + return (float64(c.bytes) * float64(c.N) / 1e6) / c.duration.Seconds() |
3002 | +} |
3003 | + |
3004 | +func (c *C) timerString() string { |
3005 | + if c.N <= 0 { |
3006 | + return fmt.Sprintf("%3.3fs", float64(c.duration.Nanoseconds())/1e9) |
3007 | + } |
3008 | + mbs := c.mbPerSec() |
3009 | + mb := "" |
3010 | + if mbs != 0 { |
3011 | + mb = fmt.Sprintf("\t%7.2f MB/s", mbs) |
3012 | + } |
3013 | + nsop := c.nsPerOp() |
3014 | + ns := fmt.Sprintf("%10d ns/op", nsop) |
3015 | + if c.N > 0 && nsop < 100 { |
3016 | + // The format specifiers here make sure that |
3017 | + // the ones digits line up for all three possible formats. |
3018 | + if nsop < 10 { |
3019 | + ns = fmt.Sprintf("%13.2f ns/op", float64(c.duration.Nanoseconds())/float64(c.N)) |
3020 | + } else { |
3021 | + ns = fmt.Sprintf("%12.1f ns/op", float64(c.duration.Nanoseconds())/float64(c.N)) |
3022 | + } |
3023 | + } |
3024 | + memStats := "" |
3025 | + if c.benchMem { |
3026 | + allocedBytes := fmt.Sprintf("%8d B/op", int64(c.netBytes)/int64(c.N)) |
3027 | + allocs := fmt.Sprintf("%8d allocs/op", int64(c.netAllocs)/int64(c.N)) |
3028 | + memStats = fmt.Sprintf("\t%s\t%s", allocedBytes, allocs) |
3029 | + } |
3030 | + return fmt.Sprintf("%8d\t%s%s%s", c.N, ns, mb, memStats) |
3031 | +} |
3032 | + |
3033 | +func min(x, y int) int { |
3034 | + if x > y { |
3035 | + return y |
3036 | + } |
3037 | + return x |
3038 | +} |
3039 | + |
3040 | +func max(x, y int) int { |
3041 | + if x < y { |
3042 | + return y |
3043 | + } |
3044 | + return x |
3045 | +} |
3046 | + |
3047 | +// roundDown10 rounds a number down to the nearest power of 10. |
3048 | +func roundDown10(n int) int { |
3049 | + var tens = 0 |
3050 | + // tens = floor(log_10(n)) |
3051 | + for n > 10 { |
3052 | + n = n / 10 |
3053 | + tens++ |
3054 | + } |
3055 | + // result = 10^tens |
3056 | + result := 1 |
3057 | + for i := 0; i < tens; i++ { |
3058 | + result *= 10 |
3059 | + } |
3060 | + return result |
3061 | +} |
3062 | + |
3063 | +// roundUp rounds x up to a number of the form [1eX, 2eX, 5eX]. |
3064 | +func roundUp(n int) int { |
3065 | + base := roundDown10(n) |
3066 | + if n < (2 * base) { |
3067 | + return 2 * base |
3068 | + } |
3069 | + if n < (5 * base) { |
3070 | + return 5 * base |
3071 | + } |
3072 | + return 10 * base |
3073 | +} |
3074 | |
3075 | === added file 'internal/gopkg.in/check.v1/benchmark_test.go' |
3076 | --- internal/gopkg.in/check.v1/benchmark_test.go 1970-01-01 00:00:00 +0000 |
3077 | +++ internal/gopkg.in/check.v1/benchmark_test.go 2015-10-30 14:12:15 +0000 |
3078 | @@ -0,0 +1,91 @@ |
3079 | +// These tests verify the test running logic. |
3080 | + |
3081 | +package check_test |
3082 | + |
3083 | +import ( |
3084 | + "time" |
3085 | + . "launchpad.net/crackly/internal/gopkg.in/check.v1" |
3086 | +) |
3087 | + |
3088 | +var benchmarkS = Suite(&BenchmarkS{}) |
3089 | + |
3090 | +type BenchmarkS struct{} |
3091 | + |
3092 | +func (s *BenchmarkS) TestCountSuite(c *C) { |
3093 | + suitesRun += 1 |
3094 | +} |
3095 | + |
3096 | +func (s *BenchmarkS) TestBasicTestTiming(c *C) { |
3097 | + helper := FixtureHelper{sleepOn: "Test1", sleep: 1000000 * time.Nanosecond} |
3098 | + output := String{} |
3099 | + runConf := RunConf{Output: &output, Verbose: true} |
3100 | + Run(&helper, &runConf) |
3101 | + |
3102 | + expected := "PASS: check_test\\.go:[0-9]+: FixtureHelper\\.Test1\t0\\.001s\n" + |
3103 | + "PASS: check_test\\.go:[0-9]+: FixtureHelper\\.Test2\t0\\.000s\n" |
3104 | + c.Assert(output.value, Matches, expected) |
3105 | +} |
3106 | + |
3107 | +func (s *BenchmarkS) TestStreamTestTiming(c *C) { |
3108 | + helper := FixtureHelper{sleepOn: "SetUpSuite", sleep: 1000000 * time.Nanosecond} |
3109 | + output := String{} |
3110 | + runConf := RunConf{Output: &output, Stream: true} |
3111 | + Run(&helper, &runConf) |
3112 | + |
3113 | + expected := "(?s).*\nPASS: check_test\\.go:[0-9]+: FixtureHelper\\.SetUpSuite\t *0\\.001s\n.*" |
3114 | + c.Assert(output.value, Matches, expected) |
3115 | +} |
3116 | + |
3117 | +func (s *BenchmarkS) TestBenchmark(c *C) { |
3118 | + helper := FixtureHelper{sleep: 100000} |
3119 | + output := String{} |
3120 | + runConf := RunConf{ |
3121 | + Output: &output, |
3122 | + Benchmark: true, |
3123 | + BenchmarkTime: 10000000, |
3124 | + Filter: "Benchmark1", |
3125 | + } |
3126 | + Run(&helper, &runConf) |
3127 | + c.Check(helper.calls[0], Equals, "SetUpSuite") |
3128 | + c.Check(helper.calls[1], Equals, "SetUpTest") |
3129 | + c.Check(helper.calls[2], Equals, "Benchmark1") |
3130 | + c.Check(helper.calls[3], Equals, "TearDownTest") |
3131 | + c.Check(helper.calls[4], Equals, "SetUpTest") |
3132 | + c.Check(helper.calls[5], Equals, "Benchmark1") |
3133 | + c.Check(helper.calls[6], Equals, "TearDownTest") |
3134 | + // ... and more. |
3135 | + |
3136 | + expected := "PASS: check_test\\.go:[0-9]+: FixtureHelper\\.Benchmark1\t *100\t *[12][0-9]{5} ns/op\n" |
3137 | + c.Assert(output.value, Matches, expected) |
3138 | +} |
3139 | + |
3140 | +func (s *BenchmarkS) TestBenchmarkBytes(c *C) { |
3141 | + helper := FixtureHelper{sleep: 100000} |
3142 | + output := String{} |
3143 | + runConf := RunConf{ |
3144 | + Output: &output, |
3145 | + Benchmark: true, |
3146 | + BenchmarkTime: 10000000, |
3147 | + Filter: "Benchmark2", |
3148 | + } |
3149 | + Run(&helper, &runConf) |
3150 | + |
3151 | + expected := "PASS: check_test\\.go:[0-9]+: FixtureHelper\\.Benchmark2\t *100\t *[12][0-9]{5} ns/op\t *[4-9]\\.[0-9]{2} MB/s\n" |
3152 | + c.Assert(output.value, Matches, expected) |
3153 | +} |
3154 | + |
3155 | +func (s *BenchmarkS) TestBenchmarkMem(c *C) { |
3156 | + helper := FixtureHelper{sleep: 100000} |
3157 | + output := String{} |
3158 | + runConf := RunConf{ |
3159 | + Output: &output, |
3160 | + Benchmark: true, |
3161 | + BenchmarkMem: true, |
3162 | + BenchmarkTime: 10000000, |
3163 | + Filter: "Benchmark3", |
3164 | + } |
3165 | + Run(&helper, &runConf) |
3166 | + |
3167 | + expected := "PASS: check_test\\.go:[0-9]+: FixtureHelper\\.Benchmark3\t *100\t *[12][0-9]{5} ns/op\t *[0-9]+ B/op\t *[1-9] allocs/op\n" |
3168 | + c.Assert(output.value, Matches, expected) |
3169 | +} |
3170 | |
3171 | === added file 'internal/gopkg.in/check.v1/bootstrap_test.go' |
3172 | --- internal/gopkg.in/check.v1/bootstrap_test.go 1970-01-01 00:00:00 +0000 |
3173 | +++ internal/gopkg.in/check.v1/bootstrap_test.go 2015-10-30 14:12:15 +0000 |
3174 | @@ -0,0 +1,82 @@ |
3175 | +// These initial tests are for bootstrapping. They verify that we can |
3176 | +// basically use the testing infrastructure itself to check if the test |
3177 | +// system is working. |
3178 | +// |
3179 | +// These tests use will break down the test runner badly in case of |
3180 | +// errors because if they simply fail, we can't be sure the developer |
3181 | +// will ever see anything (because failing means the failing system |
3182 | +// somehow isn't working! :-) |
3183 | +// |
3184 | +// Do not assume *any* internal functionality works as expected besides |
3185 | +// what's actually tested here. |
3186 | + |
3187 | +package check_test |
3188 | + |
3189 | +import ( |
3190 | + "fmt" |
3191 | + "launchpad.net/crackly/internal/gopkg.in/check.v1" |
3192 | + "strings" |
3193 | +) |
3194 | + |
3195 | +type BootstrapS struct{} |
3196 | + |
3197 | +var boostrapS = check.Suite(&BootstrapS{}) |
3198 | + |
3199 | +func (s *BootstrapS) TestCountSuite(c *check.C) { |
3200 | + suitesRun += 1 |
3201 | +} |
3202 | + |
3203 | +func (s *BootstrapS) TestFailedAndFail(c *check.C) { |
3204 | + if c.Failed() { |
3205 | + critical("c.Failed() must be false first!") |
3206 | + } |
3207 | + c.Fail() |
3208 | + if !c.Failed() { |
3209 | + critical("c.Fail() didn't put the test in a failed state!") |
3210 | + } |
3211 | + c.Succeed() |
3212 | +} |
3213 | + |
3214 | +func (s *BootstrapS) TestFailedAndSucceed(c *check.C) { |
3215 | + c.Fail() |
3216 | + c.Succeed() |
3217 | + if c.Failed() { |
3218 | + critical("c.Succeed() didn't put the test back in a non-failed state") |
3219 | + } |
3220 | +} |
3221 | + |
3222 | +func (s *BootstrapS) TestLogAndGetTestLog(c *check.C) { |
3223 | + c.Log("Hello there!") |
3224 | + log := c.GetTestLog() |
3225 | + if log != "Hello there!\n" { |
3226 | + critical(fmt.Sprintf("Log() or GetTestLog() is not working! Got: %#v", log)) |
3227 | + } |
3228 | +} |
3229 | + |
3230 | +func (s *BootstrapS) TestLogfAndGetTestLog(c *check.C) { |
3231 | + c.Logf("Hello %v", "there!") |
3232 | + log := c.GetTestLog() |
3233 | + if log != "Hello there!\n" { |
3234 | + critical(fmt.Sprintf("Logf() or GetTestLog() is not working! Got: %#v", log)) |
3235 | + } |
3236 | +} |
3237 | + |
3238 | +func (s *BootstrapS) TestRunShowsErrors(c *check.C) { |
3239 | + output := String{} |
3240 | + check.Run(&FailHelper{}, &check.RunConf{Output: &output}) |
3241 | + if strings.Index(output.value, "Expected failure!") == -1 { |
3242 | + critical(fmt.Sprintf("RunWithWriter() output did not contain the "+ |
3243 | + "expected failure! Got: %#v", |
3244 | + output.value)) |
3245 | + } |
3246 | +} |
3247 | + |
3248 | +func (s *BootstrapS) TestRunDoesntShowSuccesses(c *check.C) { |
3249 | + output := String{} |
3250 | + check.Run(&SuccessHelper{}, &check.RunConf{Output: &output}) |
3251 | + if strings.Index(output.value, "Expected success!") != -1 { |
3252 | + critical(fmt.Sprintf("RunWithWriter() output contained a successful "+ |
3253 | + "test! Got: %#v", |
3254 | + output.value)) |
3255 | + } |
3256 | +} |
3257 | |
3258 | === added file 'internal/gopkg.in/check.v1/check.go' |
3259 | --- internal/gopkg.in/check.v1/check.go 1970-01-01 00:00:00 +0000 |
3260 | +++ internal/gopkg.in/check.v1/check.go 2015-10-30 14:12:15 +0000 |
3261 | @@ -0,0 +1,945 @@ |
3262 | +// Package check is a rich testing extension for Go's testing package. |
3263 | +// |
3264 | +// For details about the project, see: |
3265 | +// |
3266 | +// http://labix.org/gocheck |
3267 | +// |
3268 | +package check |
3269 | + |
3270 | +import ( |
3271 | + "bytes" |
3272 | + "errors" |
3273 | + "fmt" |
3274 | + "io" |
3275 | + "math/rand" |
3276 | + "os" |
3277 | + "path" |
3278 | + "path/filepath" |
3279 | + "reflect" |
3280 | + "regexp" |
3281 | + "runtime" |
3282 | + "strconv" |
3283 | + "strings" |
3284 | + "sync" |
3285 | + "time" |
3286 | +) |
3287 | + |
3288 | +// ----------------------------------------------------------------------- |
3289 | +// Internal type which deals with suite method calling. |
3290 | + |
3291 | +const ( |
3292 | + fixtureKd = iota |
3293 | + testKd |
3294 | +) |
3295 | + |
3296 | +type funcKind int |
3297 | + |
3298 | +const ( |
3299 | + succeededSt = iota |
3300 | + failedSt |
3301 | + skippedSt |
3302 | + panickedSt |
3303 | + fixturePanickedSt |
3304 | + missedSt |
3305 | +) |
3306 | + |
3307 | +type funcStatus int |
3308 | + |
3309 | +// A method value can't reach its own Method structure. |
3310 | +type methodType struct { |
3311 | + reflect.Value |
3312 | + Info reflect.Method |
3313 | +} |
3314 | + |
3315 | +func newMethod(receiver reflect.Value, i int) *methodType { |
3316 | + return &methodType{receiver.Method(i), receiver.Type().Method(i)} |
3317 | +} |
3318 | + |
3319 | +func (method *methodType) PC() uintptr { |
3320 | + return method.Info.Func.Pointer() |
3321 | +} |
3322 | + |
3323 | +func (method *methodType) suiteName() string { |
3324 | + t := method.Info.Type.In(0) |
3325 | + if t.Kind() == reflect.Ptr { |
3326 | + t = t.Elem() |
3327 | + } |
3328 | + return t.Name() |
3329 | +} |
3330 | + |
3331 | +func (method *methodType) String() string { |
3332 | + return method.suiteName() + "." + method.Info.Name |
3333 | +} |
3334 | + |
3335 | +func (method *methodType) matches(re *regexp.Regexp) bool { |
3336 | + return (re.MatchString(method.Info.Name) || |
3337 | + re.MatchString(method.suiteName()) || |
3338 | + re.MatchString(method.String())) |
3339 | +} |
3340 | + |
3341 | +type C struct { |
3342 | + method *methodType |
3343 | + kind funcKind |
3344 | + testName string |
3345 | + status funcStatus |
3346 | + logb *logger |
3347 | + logw io.Writer |
3348 | + done chan *C |
3349 | + reason string |
3350 | + mustFail bool |
3351 | + tempDir *tempDir |
3352 | + benchMem bool |
3353 | + startTime time.Time |
3354 | + timer |
3355 | +} |
3356 | + |
3357 | +func (c *C) stopNow() { |
3358 | + runtime.Goexit() |
3359 | +} |
3360 | + |
3361 | +// logger is a concurrency safe byte.Buffer |
3362 | +type logger struct { |
3363 | + sync.Mutex |
3364 | + writer bytes.Buffer |
3365 | +} |
3366 | + |
3367 | +func (l *logger) Write(buf []byte) (int, error) { |
3368 | + l.Lock() |
3369 | + defer l.Unlock() |
3370 | + return l.writer.Write(buf) |
3371 | +} |
3372 | + |
3373 | +func (l *logger) WriteTo(w io.Writer) (int64, error) { |
3374 | + l.Lock() |
3375 | + defer l.Unlock() |
3376 | + return l.writer.WriteTo(w) |
3377 | +} |
3378 | + |
3379 | +func (l *logger) String() string { |
3380 | + l.Lock() |
3381 | + defer l.Unlock() |
3382 | + return l.writer.String() |
3383 | +} |
3384 | + |
3385 | +// ----------------------------------------------------------------------- |
3386 | +// Handling of temporary files and directories. |
3387 | + |
3388 | +type tempDir struct { |
3389 | + sync.Mutex |
3390 | + path string |
3391 | + counter int |
3392 | +} |
3393 | + |
3394 | +func (td *tempDir) newPath() string { |
3395 | + td.Lock() |
3396 | + defer td.Unlock() |
3397 | + if td.path == "" { |
3398 | + var err error |
3399 | + for i := 0; i != 100; i++ { |
3400 | + path := fmt.Sprintf("%s%ccheck-%d", os.TempDir(), os.PathSeparator, rand.Int()) |
3401 | + if err = os.Mkdir(path, 0700); err == nil { |
3402 | + td.path = path |
3403 | + break |
3404 | + } |
3405 | + } |
3406 | + if td.path == "" { |
3407 | + panic("Couldn't create temporary directory: " + err.Error()) |
3408 | + } |
3409 | + } |
3410 | + result := filepath.Join(td.path, strconv.Itoa(td.counter)) |
3411 | + td.counter += 1 |
3412 | + return result |
3413 | +} |
3414 | + |
3415 | +func (td *tempDir) removeAll() { |
3416 | + td.Lock() |
3417 | + defer td.Unlock() |
3418 | + if td.path != "" { |
3419 | + err := os.RemoveAll(td.path) |
3420 | + if err != nil { |
3421 | + fmt.Fprintf(os.Stderr, "WARNING: Error cleaning up temporaries: "+err.Error()) |
3422 | + } |
3423 | + } |
3424 | +} |
3425 | + |
3426 | +// Create a new temporary directory which is automatically removed after |
3427 | +// the suite finishes running. |
3428 | +func (c *C) MkDir() string { |
3429 | + path := c.tempDir.newPath() |
3430 | + if err := os.Mkdir(path, 0700); err != nil { |
3431 | + panic(fmt.Sprintf("Couldn't create temporary directory %s: %s", path, err.Error())) |
3432 | + } |
3433 | + return path |
3434 | +} |
3435 | + |
3436 | +// ----------------------------------------------------------------------- |
3437 | +// Low-level logging functions. |
3438 | + |
3439 | +func (c *C) log(args ...interface{}) { |
3440 | + c.writeLog([]byte(fmt.Sprint(args...) + "\n")) |
3441 | +} |
3442 | + |
3443 | +func (c *C) logf(format string, args ...interface{}) { |
3444 | + c.writeLog([]byte(fmt.Sprintf(format+"\n", args...))) |
3445 | +} |
3446 | + |
3447 | +func (c *C) logNewLine() { |
3448 | + c.writeLog([]byte{'\n'}) |
3449 | +} |
3450 | + |
3451 | +func (c *C) writeLog(buf []byte) { |
3452 | + c.logb.Write(buf) |
3453 | + if c.logw != nil { |
3454 | + c.logw.Write(buf) |
3455 | + } |
3456 | +} |
3457 | + |
3458 | +func hasStringOrError(x interface{}) (ok bool) { |
3459 | + _, ok = x.(fmt.Stringer) |
3460 | + if ok { |
3461 | + return |
3462 | + } |
3463 | + _, ok = x.(error) |
3464 | + return |
3465 | +} |
3466 | + |
3467 | +func (c *C) logValue(label string, value interface{}) { |
3468 | + if label == "" { |
3469 | + if hasStringOrError(value) { |
3470 | + c.logf("... %#v (%q)", value, value) |
3471 | + } else { |
3472 | + c.logf("... %#v", value) |
3473 | + } |
3474 | + } else if value == nil { |
3475 | + c.logf("... %s = nil", label) |
3476 | + } else { |
3477 | + if hasStringOrError(value) { |
3478 | + fv := fmt.Sprintf("%#v", value) |
3479 | + qv := fmt.Sprintf("%q", value) |
3480 | + if fv != qv { |
3481 | + c.logf("... %s %s = %s (%s)", label, reflect.TypeOf(value), fv, qv) |
3482 | + return |
3483 | + } |
3484 | + } |
3485 | + if s, ok := value.(string); ok && isMultiLine(s) { |
3486 | + c.logf(`... %s %s = "" +`, label, reflect.TypeOf(value)) |
3487 | + c.logMultiLine(s) |
3488 | + } else { |
3489 | + c.logf("... %s %s = %#v", label, reflect.TypeOf(value), value) |
3490 | + } |
3491 | + } |
3492 | +} |
3493 | + |
3494 | +func (c *C) logMultiLine(s string) { |
3495 | + b := make([]byte, 0, len(s)*2) |
3496 | + i := 0 |
3497 | + n := len(s) |
3498 | + for i < n { |
3499 | + j := i + 1 |
3500 | + for j < n && s[j-1] != '\n' { |
3501 | + j++ |
3502 | + } |
3503 | + b = append(b, "... "...) |
3504 | + b = strconv.AppendQuote(b, s[i:j]) |
3505 | + if j < n { |
3506 | + b = append(b, " +"...) |
3507 | + } |
3508 | + b = append(b, '\n') |
3509 | + i = j |
3510 | + } |
3511 | + c.writeLog(b) |
3512 | +} |
3513 | + |
3514 | +func isMultiLine(s string) bool { |
3515 | + for i := 0; i+1 < len(s); i++ { |
3516 | + if s[i] == '\n' { |
3517 | + return true |
3518 | + } |
3519 | + } |
3520 | + return false |
3521 | +} |
3522 | + |
3523 | +func (c *C) logString(issue string) { |
3524 | + c.log("... ", issue) |
3525 | +} |
3526 | + |
3527 | +func (c *C) logCaller(skip int) { |
3528 | + // This is a bit heavier than it ought to be. |
3529 | + skip += 1 // Our own frame. |
3530 | + pc, callerFile, callerLine, ok := runtime.Caller(skip) |
3531 | + if !ok { |
3532 | + return |
3533 | + } |
3534 | + var testFile string |
3535 | + var testLine int |
3536 | + testFunc := runtime.FuncForPC(c.method.PC()) |
3537 | + if runtime.FuncForPC(pc) != testFunc { |
3538 | + for { |
3539 | + skip += 1 |
3540 | + if pc, file, line, ok := runtime.Caller(skip); ok { |
3541 | + // Note that the test line may be different on |
3542 | + // distinct calls for the same test. Showing |
3543 | + // the "internal" line is helpful when debugging. |
3544 | + if runtime.FuncForPC(pc) == testFunc { |
3545 | + testFile, testLine = file, line |
3546 | + break |
3547 | + } |
3548 | + } else { |
3549 | + break |
3550 | + } |
3551 | + } |
3552 | + } |
3553 | + if testFile != "" && (testFile != callerFile || testLine != callerLine) { |
3554 | + c.logCode(testFile, testLine) |
3555 | + } |
3556 | + c.logCode(callerFile, callerLine) |
3557 | +} |
3558 | + |
3559 | +func (c *C) logCode(path string, line int) { |
3560 | + c.logf("%s:%d:", nicePath(path), line) |
3561 | + code, err := printLine(path, line) |
3562 | + if code == "" { |
3563 | + code = "..." // XXX Open the file and take the raw line. |
3564 | + if err != nil { |
3565 | + code += err.Error() |
3566 | + } |
3567 | + } |
3568 | + c.log(indent(code, " ")) |
3569 | +} |
3570 | + |
3571 | +var valueGo = filepath.Join("reflect", "value.go") |
3572 | +var asmGo = filepath.Join("runtime", "asm_") |
3573 | + |
3574 | +func (c *C) logPanic(skip int, value interface{}) { |
3575 | + skip++ // Our own frame. |
3576 | + initialSkip := skip |
3577 | + for ; ; skip++ { |
3578 | + if pc, file, line, ok := runtime.Caller(skip); ok { |
3579 | + if skip == initialSkip { |
3580 | + c.logf("... Panic: %s (PC=0x%X)\n", value, pc) |
3581 | + } |
3582 | + name := niceFuncName(pc) |
3583 | + path := nicePath(file) |
3584 | + if strings.Contains(path, "/gopkg.in/check.v") { |
3585 | + continue |
3586 | + } |
3587 | + if name == "Value.call" && strings.HasSuffix(path, valueGo) { |
3588 | + continue |
3589 | + } |
3590 | + if name == "call16" && strings.Contains(path, asmGo) { |
3591 | + continue |
3592 | + } |
3593 | + c.logf("%s:%d\n in %s", nicePath(file), line, name) |
3594 | + } else { |
3595 | + break |
3596 | + } |
3597 | + } |
3598 | +} |
3599 | + |
3600 | +func (c *C) logSoftPanic(issue string) { |
3601 | + c.log("... Panic: ", issue) |
3602 | +} |
3603 | + |
3604 | +func (c *C) logArgPanic(method *methodType, expectedType string) { |
3605 | + c.logf("... Panic: %s argument should be %s", |
3606 | + niceFuncName(method.PC()), expectedType) |
3607 | +} |
3608 | + |
3609 | +// ----------------------------------------------------------------------- |
3610 | +// Some simple formatting helpers. |
3611 | + |
3612 | +var initWD, initWDErr = os.Getwd() |
3613 | + |
3614 | +func init() { |
3615 | + if initWDErr == nil { |
3616 | + initWD = strings.Replace(initWD, "\\", "/", -1) + "/" |
3617 | + } |
3618 | +} |
3619 | + |
3620 | +func nicePath(path string) string { |
3621 | + if initWDErr == nil { |
3622 | + if strings.HasPrefix(path, initWD) { |
3623 | + return path[len(initWD):] |
3624 | + } |
3625 | + } |
3626 | + return path |
3627 | +} |
3628 | + |
3629 | +func niceFuncPath(pc uintptr) string { |
3630 | + function := runtime.FuncForPC(pc) |
3631 | + if function != nil { |
3632 | + filename, line := function.FileLine(pc) |
3633 | + return fmt.Sprintf("%s:%d", nicePath(filename), line) |
3634 | + } |
3635 | + return "<unknown path>" |
3636 | +} |
3637 | + |
3638 | +func niceFuncName(pc uintptr) string { |
3639 | + function := runtime.FuncForPC(pc) |
3640 | + if function != nil { |
3641 | + name := path.Base(function.Name()) |
3642 | + if i := strings.Index(name, "."); i > 0 { |
3643 | + name = name[i+1:] |
3644 | + } |
3645 | + if strings.HasPrefix(name, "(*") { |
3646 | + if i := strings.Index(name, ")"); i > 0 { |
3647 | + name = name[2:i] + name[i+1:] |
3648 | + } |
3649 | + } |
3650 | + if i := strings.LastIndex(name, ".*"); i != -1 { |
3651 | + name = name[:i] + "." + name[i+2:] |
3652 | + } |
3653 | + if i := strings.LastIndex(name, "·"); i != -1 { |
3654 | + name = name[:i] + "." + name[i+2:] |
3655 | + } |
3656 | + return name |
3657 | + } |
3658 | + return "<unknown function>" |
3659 | +} |
3660 | + |
3661 | +// ----------------------------------------------------------------------- |
3662 | +// Result tracker to aggregate call results. |
3663 | + |
3664 | +type Result struct { |
3665 | + Succeeded int |
3666 | + Failed int |
3667 | + Skipped int |
3668 | + Panicked int |
3669 | + FixturePanicked int |
3670 | + ExpectedFailures int |
3671 | + Missed int // Not even tried to run, related to a panic in the fixture. |
3672 | + RunError error // Houston, we've got a problem. |
3673 | + WorkDir string // If KeepWorkDir is true |
3674 | +} |
3675 | + |
3676 | +type resultTracker struct { |
3677 | + result Result |
3678 | + _lastWasProblem bool |
3679 | + _waiting int |
3680 | + _missed int |
3681 | + _expectChan chan *C |
3682 | + _doneChan chan *C |
3683 | + _stopChan chan bool |
3684 | +} |
3685 | + |
3686 | +func newResultTracker() *resultTracker { |
3687 | + return &resultTracker{_expectChan: make(chan *C), // Synchronous |
3688 | + _doneChan: make(chan *C, 32), // Asynchronous |
3689 | + _stopChan: make(chan bool)} // Synchronous |
3690 | +} |
3691 | + |
3692 | +func (tracker *resultTracker) start() { |
3693 | + go tracker._loopRoutine() |
3694 | +} |
3695 | + |
3696 | +func (tracker *resultTracker) waitAndStop() { |
3697 | + <-tracker._stopChan |
3698 | +} |
3699 | + |
3700 | +func (tracker *resultTracker) expectCall(c *C) { |
3701 | + tracker._expectChan <- c |
3702 | +} |
3703 | + |
3704 | +func (tracker *resultTracker) callDone(c *C) { |
3705 | + tracker._doneChan <- c |
3706 | +} |
3707 | + |
3708 | +func (tracker *resultTracker) _loopRoutine() { |
3709 | + for { |
3710 | + var c *C |
3711 | + if tracker._waiting > 0 { |
3712 | + // Calls still running. Can't stop. |
3713 | + select { |
3714 | + // XXX Reindent this (not now to make diff clear) |
3715 | + case c = <-tracker._expectChan: |
3716 | + tracker._waiting += 1 |
3717 | + case c = <-tracker._doneChan: |
3718 | + tracker._waiting -= 1 |
3719 | + switch c.status { |
3720 | + case succeededSt: |
3721 | + if c.kind == testKd { |
3722 | + if c.mustFail { |
3723 | + tracker.result.ExpectedFailures++ |
3724 | + } else { |
3725 | + tracker.result.Succeeded++ |
3726 | + } |
3727 | + } |
3728 | + case failedSt: |
3729 | + tracker.result.Failed++ |
3730 | + case panickedSt: |
3731 | + if c.kind == fixtureKd { |
3732 | + tracker.result.FixturePanicked++ |
3733 | + } else { |
3734 | + tracker.result.Panicked++ |
3735 | + } |
3736 | + case fixturePanickedSt: |
3737 | + // Track it as missed, since the panic |
3738 | + // was on the fixture, not on the test. |
3739 | + tracker.result.Missed++ |
3740 | + case missedSt: |
3741 | + tracker.result.Missed++ |
3742 | + case skippedSt: |
3743 | + if c.kind == testKd { |
3744 | + tracker.result.Skipped++ |
3745 | + } |
3746 | + } |
3747 | + } |
3748 | + } else { |
3749 | + // No calls. Can stop, but no done calls here. |
3750 | + select { |
3751 | + case tracker._stopChan <- true: |
3752 | + return |
3753 | + case c = <-tracker._expectChan: |
3754 | + tracker._waiting += 1 |
3755 | + case c = <-tracker._doneChan: |
3756 | + panic("Tracker got an unexpected done call.") |
3757 | + } |
3758 | + } |
3759 | + } |
3760 | +} |
3761 | + |
3762 | +// ----------------------------------------------------------------------- |
3763 | +// The underlying suite runner. |
3764 | + |
3765 | +type suiteRunner struct { |
3766 | + suite interface{} |
3767 | + setUpSuite, tearDownSuite *methodType |
3768 | + setUpTest, tearDownTest *methodType |
3769 | + tests []*methodType |
3770 | + tracker *resultTracker |
3771 | + tempDir *tempDir |
3772 | + keepDir bool |
3773 | + output *outputWriter |
3774 | + reportedProblemLast bool |
3775 | + benchTime time.Duration |
3776 | + benchMem bool |
3777 | +} |
3778 | + |
3779 | +type RunConf struct { |
3780 | + Output io.Writer |
3781 | + Stream bool |
3782 | + Verbose bool |
3783 | + Filter string |
3784 | + Benchmark bool |
3785 | + BenchmarkTime time.Duration // Defaults to 1 second |
3786 | + BenchmarkMem bool |
3787 | + KeepWorkDir bool |
3788 | +} |
3789 | + |
3790 | +// Create a new suiteRunner able to run all methods in the given suite. |
3791 | +func newSuiteRunner(suite interface{}, runConf *RunConf) *suiteRunner { |
3792 | + var conf RunConf |
3793 | + if runConf != nil { |
3794 | + conf = *runConf |
3795 | + } |
3796 | + if conf.Output == nil { |
3797 | + conf.Output = os.Stdout |
3798 | + } |
3799 | + if conf.Benchmark { |
3800 | + conf.Verbose = true |
3801 | + } |
3802 | + |
3803 | + suiteType := reflect.TypeOf(suite) |
3804 | + suiteNumMethods := suiteType.NumMethod() |
3805 | + suiteValue := reflect.ValueOf(suite) |
3806 | + |
3807 | + runner := &suiteRunner{ |
3808 | + suite: suite, |
3809 | + output: newOutputWriter(conf.Output, conf.Stream, conf.Verbose), |
3810 | + tracker: newResultTracker(), |
3811 | + benchTime: conf.BenchmarkTime, |
3812 | + benchMem: conf.BenchmarkMem, |
3813 | + tempDir: &tempDir{}, |
3814 | + keepDir: conf.KeepWorkDir, |
3815 | + tests: make([]*methodType, 0, suiteNumMethods), |
3816 | + } |
3817 | + if runner.benchTime == 0 { |
3818 | + runner.benchTime = 1 * time.Second |
3819 | + } |
3820 | + |
3821 | + var filterRegexp *regexp.Regexp |
3822 | + if conf.Filter != "" { |
3823 | + if regexp, err := regexp.Compile(conf.Filter); err != nil { |
3824 | + msg := "Bad filter expression: " + err.Error() |
3825 | + runner.tracker.result.RunError = errors.New(msg) |
3826 | + return runner |
3827 | + } else { |
3828 | + filterRegexp = regexp |
3829 | + } |
3830 | + } |
3831 | + |
3832 | + for i := 0; i != suiteNumMethods; i++ { |
3833 | + method := newMethod(suiteValue, i) |
3834 | + switch method.Info.Name { |
3835 | + case "SetUpSuite": |
3836 | + runner.setUpSuite = method |
3837 | + case "TearDownSuite": |
3838 | + runner.tearDownSuite = method |
3839 | + case "SetUpTest": |
3840 | + runner.setUpTest = method |
3841 | + case "TearDownTest": |
3842 | + runner.tearDownTest = method |
3843 | + default: |
3844 | + prefix := "Test" |
3845 | + if conf.Benchmark { |
3846 | + prefix = "Benchmark" |
3847 | + } |
3848 | + if !strings.HasPrefix(method.Info.Name, prefix) { |
3849 | + continue |
3850 | + } |
3851 | + if filterRegexp == nil || method.matches(filterRegexp) { |
3852 | + runner.tests = append(runner.tests, method) |
3853 | + } |
3854 | + } |
3855 | + } |
3856 | + return runner |
3857 | +} |
3858 | + |
3859 | +// Run all methods in the given suite. |
3860 | +func (runner *suiteRunner) run() *Result { |
3861 | + if runner.tracker.result.RunError == nil && len(runner.tests) > 0 { |
3862 | + runner.tracker.start() |
3863 | + if runner.checkFixtureArgs() { |
3864 | + c := runner.runFixture(runner.setUpSuite, "", nil) |
3865 | + if c == nil || c.status == succeededSt { |
3866 | + for i := 0; i != len(runner.tests); i++ { |
3867 | + c := runner.runTest(runner.tests[i]) |
3868 | + if c.status == fixturePanickedSt { |
3869 | + runner.skipTests(missedSt, runner.tests[i+1:]) |
3870 | + break |
3871 | + } |
3872 | + } |
3873 | + } else if c != nil && c.status == skippedSt { |
3874 | + runner.skipTests(skippedSt, runner.tests) |
3875 | + } else { |
3876 | + runner.skipTests(missedSt, runner.tests) |
3877 | + } |
3878 | + runner.runFixture(runner.tearDownSuite, "", nil) |
3879 | + } else { |
3880 | + runner.skipTests(missedSt, runner.tests) |
3881 | + } |
3882 | + runner.tracker.waitAndStop() |
3883 | + if runner.keepDir { |
3884 | + runner.tracker.result.WorkDir = runner.tempDir.path |
3885 | + } else { |
3886 | + runner.tempDir.removeAll() |
3887 | + } |
3888 | + } |
3889 | + return &runner.tracker.result |
3890 | +} |
3891 | + |
3892 | +// Create a call object with the given suite method, and fork a |
3893 | +// goroutine with the provided dispatcher for running it. |
3894 | +func (runner *suiteRunner) forkCall(method *methodType, kind funcKind, testName string, logb *logger, dispatcher func(c *C)) *C { |
3895 | + var logw io.Writer |
3896 | + if runner.output.Stream { |
3897 | + logw = runner.output |
3898 | + } |
3899 | + if logb == nil { |
3900 | + logb = new(logger) |
3901 | + } |
3902 | + c := &C{ |
3903 | + method: method, |
3904 | + kind: kind, |
3905 | + testName: testName, |
3906 | + logb: logb, |
3907 | + logw: logw, |
3908 | + tempDir: runner.tempDir, |
3909 | + done: make(chan *C, 1), |
3910 | + timer: timer{benchTime: runner.benchTime}, |
3911 | + startTime: time.Now(), |
3912 | + benchMem: runner.benchMem, |
3913 | + } |
3914 | + runner.tracker.expectCall(c) |
3915 | + go (func() { |
3916 | + runner.reportCallStarted(c) |
3917 | + defer runner.callDone(c) |
3918 | + dispatcher(c) |
3919 | + })() |
3920 | + return c |
3921 | +} |
3922 | + |
3923 | +// Same as forkCall(), but wait for call to finish before returning. |
3924 | +func (runner *suiteRunner) runFunc(method *methodType, kind funcKind, testName string, logb *logger, dispatcher func(c *C)) *C { |
3925 | + c := runner.forkCall(method, kind, testName, logb, dispatcher) |
3926 | + <-c.done |
3927 | + return c |
3928 | +} |
3929 | + |
3930 | +// Handle a finished call. If there were any panics, update the call status |
3931 | +// accordingly. Then, mark the call as done and report to the tracker. |
3932 | +func (runner *suiteRunner) callDone(c *C) { |
3933 | + value := recover() |
3934 | + if value != nil { |
3935 | + switch v := value.(type) { |
3936 | + case *fixturePanic: |
3937 | + if v.status == skippedSt { |
3938 | + c.status = skippedSt |
3939 | + } else { |
3940 | + c.logSoftPanic("Fixture has panicked (see related PANIC)") |
3941 | + c.status = fixturePanickedSt |
3942 | + } |
3943 | + default: |
3944 | + c.logPanic(1, value) |
3945 | + c.status = panickedSt |
3946 | + } |
3947 | + } |
3948 | + if c.mustFail { |
3949 | + switch c.status { |
3950 | + case failedSt: |
3951 | + c.status = succeededSt |
3952 | + case succeededSt: |
3953 | + c.status = failedSt |
3954 | + c.logString("Error: Test succeeded, but was expected to fail") |
3955 | + c.logString("Reason: " + c.reason) |
3956 | + } |
3957 | + } |
3958 | + |
3959 | + runner.reportCallDone(c) |
3960 | + c.done <- c |
3961 | +} |
3962 | + |
3963 | +// Runs a fixture call synchronously. The fixture will still be run in a |
3964 | +// goroutine like all suite methods, but this method will not return |
3965 | +// while the fixture goroutine is not done, because the fixture must be |
3966 | +// run in a desired order. |
3967 | +func (runner *suiteRunner) runFixture(method *methodType, testName string, logb *logger) *C { |
3968 | + if method != nil { |
3969 | + c := runner.runFunc(method, fixtureKd, testName, logb, func(c *C) { |
3970 | + c.ResetTimer() |
3971 | + c.StartTimer() |
3972 | + defer c.StopTimer() |
3973 | + c.method.Call([]reflect.Value{reflect.ValueOf(c)}) |
3974 | + }) |
3975 | + return c |
3976 | + } |
3977 | + return nil |
3978 | +} |
3979 | + |
3980 | +// Run the fixture method with runFixture(), but panic with a fixturePanic{} |
3981 | +// in case the fixture method panics. This makes it easier to track the |
3982 | +// fixture panic together with other call panics within forkTest(). |
3983 | +func (runner *suiteRunner) runFixtureWithPanic(method *methodType, testName string, logb *logger, skipped *bool) *C { |
3984 | + if skipped != nil && *skipped { |
3985 | + return nil |
3986 | + } |
3987 | + c := runner.runFixture(method, testName, logb) |
3988 | + if c != nil && c.status != succeededSt { |
3989 | + if skipped != nil { |
3990 | + *skipped = c.status == skippedSt |
3991 | + } |
3992 | + panic(&fixturePanic{c.status, method}) |
3993 | + } |
3994 | + return c |
3995 | +} |
3996 | + |
3997 | +type fixturePanic struct { |
3998 | + status funcStatus |
3999 | + method *methodType |
4000 | +} |
4001 | + |
4002 | +// Run the suite test method, together with the test-specific fixture, |
4003 | +// asynchronously. |
4004 | +func (runner *suiteRunner) forkTest(method *methodType) *C { |
4005 | + testName := method.String() |
4006 | + return runner.forkCall(method, testKd, testName, nil, func(c *C) { |
4007 | + var skipped bool |
4008 | + defer runner.runFixtureWithPanic(runner.tearDownTest, testName, nil, &skipped) |
4009 | + defer c.StopTimer() |
4010 | + benchN := 1 |
4011 | + for { |
4012 | + runner.runFixtureWithPanic(runner.setUpTest, testName, c.logb, &skipped) |
4013 | + mt := c.method.Type() |
4014 | + if mt.NumIn() != 1 || mt.In(0) != reflect.TypeOf(c) { |
4015 | + // Rather than a plain panic, provide a more helpful message when |
4016 | + // the argument type is incorrect. |
4017 | + c.status = panickedSt |
4018 | + c.logArgPanic(c.method, "*check.C") |
4019 | + return |
4020 | + } |
4021 | + if strings.HasPrefix(c.method.Info.Name, "Test") { |
4022 | + c.ResetTimer() |
4023 | + c.StartTimer() |
4024 | + c.method.Call([]reflect.Value{reflect.ValueOf(c)}) |
4025 | + return |
4026 | + } |
4027 | + if !strings.HasPrefix(c.method.Info.Name, "Benchmark") { |
4028 | + panic("unexpected method prefix: " + c.method.Info.Name) |
4029 | + } |
4030 | + |
4031 | + runtime.GC() |
4032 | + c.N = benchN |
4033 | + c.ResetTimer() |
4034 | + c.StartTimer() |
4035 | + c.method.Call([]reflect.Value{reflect.ValueOf(c)}) |
4036 | + c.StopTimer() |
4037 | + if c.status != succeededSt || c.duration >= c.benchTime || benchN >= 1e9 { |
4038 | + return |
4039 | + } |
4040 | + perOpN := int(1e9) |
4041 | + if c.nsPerOp() != 0 { |
4042 | + perOpN = int(c.benchTime.Nanoseconds() / c.nsPerOp()) |
4043 | + } |
4044 | + |
4045 | + // Logic taken from the stock testing package: |
4046 | + // - Run more iterations than we think we'll need for a second (1.5x). |
4047 | + // - Don't grow too fast in case we had timing errors previously. |
4048 | + // - Be sure to run at least one more than last time. |
4049 | + benchN = max(min(perOpN+perOpN/2, 100*benchN), benchN+1) |
4050 | + benchN = roundUp(benchN) |
4051 | + |
4052 | + skipped = true // Don't run the deferred one if this panics. |
4053 | + runner.runFixtureWithPanic(runner.tearDownTest, testName, nil, nil) |
4054 | + skipped = false |
4055 | + } |
4056 | + }) |
4057 | +} |
4058 | + |
4059 | +// Same as forkTest(), but wait for the test to finish before returning. |
4060 | +func (runner *suiteRunner) runTest(method *methodType) *C { |
4061 | + c := runner.forkTest(method) |
4062 | + <-c.done |
4063 | + return c |
4064 | +} |
4065 | + |
4066 | +// Helper to mark tests as skipped or missed. A bit heavy for what |
4067 | +// it does, but it enables homogeneous handling of tracking, including |
4068 | +// nice verbose output. |
4069 | +func (runner *suiteRunner) skipTests(status funcStatus, methods []*methodType) { |
4070 | + for _, method := range methods { |
4071 | + runner.runFunc(method, testKd, "", nil, func(c *C) { |
4072 | + c.status = status |
4073 | + }) |
4074 | + } |
4075 | +} |
4076 | + |
4077 | +// Verify if the fixture arguments are *check.C. In case of errors, |
4078 | +// log the error as a panic in the fixture method call, and return false. |
4079 | +func (runner *suiteRunner) checkFixtureArgs() bool { |
4080 | + succeeded := true |
4081 | + argType := reflect.TypeOf(&C{}) |
4082 | + for _, method := range []*methodType{runner.setUpSuite, runner.tearDownSuite, runner.setUpTest, runner.tearDownTest} { |
4083 | + if method != nil { |
4084 | + mt := method.Type() |
4085 | + if mt.NumIn() != 1 || mt.In(0) != argType { |
4086 | + succeeded = false |
4087 | + runner.runFunc(method, fixtureKd, "", nil, func(c *C) { |
4088 | + c.logArgPanic(method, "*check.C") |
4089 | + c.status = panickedSt |
4090 | + }) |
4091 | + } |
4092 | + } |
4093 | + } |
4094 | + return succeeded |
4095 | +} |
4096 | + |
4097 | +func (runner *suiteRunner) reportCallStarted(c *C) { |
4098 | + runner.output.WriteCallStarted("START", c) |
4099 | +} |
4100 | + |
4101 | +func (runner *suiteRunner) reportCallDone(c *C) { |
4102 | + runner.tracker.callDone(c) |
4103 | + switch c.status { |
4104 | + case succeededSt: |
4105 | + if c.mustFail { |
4106 | + runner.output.WriteCallSuccess("FAIL EXPECTED", c) |
4107 | + } else { |
4108 | + runner.output.WriteCallSuccess("PASS", c) |
4109 | + } |
4110 | + case skippedSt: |
4111 | + runner.output.WriteCallSuccess("SKIP", c) |
4112 | + case failedSt: |
4113 | + runner.output.WriteCallProblem("FAIL", c) |
4114 | + case panickedSt: |
4115 | + runner.output.WriteCallProblem("PANIC", c) |
4116 | + case fixturePanickedSt: |
4117 | + // That's a testKd call reporting that its fixture |
4118 | + // has panicked. The fixture call which caused the |
4119 | + // panic itself was tracked above. We'll report to |
4120 | + // aid debugging. |
4121 | + runner.output.WriteCallProblem("PANIC", c) |
4122 | + case missedSt: |
4123 | + runner.output.WriteCallSuccess("MISS", c) |
4124 | + } |
4125 | +} |
4126 | + |
4127 | +// ----------------------------------------------------------------------- |
4128 | +// Output writer manages atomic output writing according to settings. |
4129 | + |
4130 | +type outputWriter struct { |
4131 | + m sync.Mutex |
4132 | + writer io.Writer |
4133 | + wroteCallProblemLast bool |
4134 | + Stream bool |
4135 | + Verbose bool |
4136 | +} |
4137 | + |
4138 | +func newOutputWriter(writer io.Writer, stream, verbose bool) *outputWriter { |
4139 | + return &outputWriter{writer: writer, Stream: stream, Verbose: verbose} |
4140 | +} |
4141 | + |
4142 | +func (ow *outputWriter) Write(content []byte) (n int, err error) { |
4143 | + ow.m.Lock() |
4144 | + n, err = ow.writer.Write(content) |
4145 | + ow.m.Unlock() |
4146 | + return |
4147 | +} |
4148 | + |
4149 | +func (ow *outputWriter) WriteCallStarted(label string, c *C) { |
4150 | + if ow.Stream { |
4151 | + header := renderCallHeader(label, c, "", "\n") |
4152 | + ow.m.Lock() |
4153 | + ow.writer.Write([]byte(header)) |
4154 | + ow.m.Unlock() |
4155 | + } |
4156 | +} |
4157 | + |
4158 | +func (ow *outputWriter) WriteCallProblem(label string, c *C) { |
4159 | + var prefix string |
4160 | + if !ow.Stream { |
4161 | + prefix = "\n-----------------------------------" + |
4162 | + "-----------------------------------\n" |
4163 | + } |
4164 | + header := renderCallHeader(label, c, prefix, "\n\n") |
4165 | + ow.m.Lock() |
4166 | + ow.wroteCallProblemLast = true |
4167 | + ow.writer.Write([]byte(header)) |
4168 | + if !ow.Stream { |
4169 | + c.logb.WriteTo(ow.writer) |
4170 | + } |
4171 | + ow.m.Unlock() |
4172 | +} |
4173 | + |
4174 | +func (ow *outputWriter) WriteCallSuccess(label string, c *C) { |
4175 | + if ow.Stream || (ow.Verbose && c.kind == testKd) { |
4176 | + // TODO Use a buffer here. |
4177 | + var suffix string |
4178 | + if c.reason != "" { |
4179 | + suffix = " (" + c.reason + ")" |
4180 | + } |
4181 | + if c.status == succeededSt { |
4182 | + suffix += "\t" + c.timerString() |
4183 | + } |
4184 | + suffix += "\n" |
4185 | + if ow.Stream { |
4186 | + suffix += "\n" |
4187 | + } |
4188 | + header := renderCallHeader(label, c, "", suffix) |
4189 | + ow.m.Lock() |
4190 | + // Resist temptation of using line as prefix above due to race. |
4191 | + if !ow.Stream && ow.wroteCallProblemLast { |
4192 | + header = "\n-----------------------------------" + |
4193 | + "-----------------------------------\n" + |
4194 | + header |
4195 | + } |
4196 | + ow.wroteCallProblemLast = false |
4197 | + ow.writer.Write([]byte(header)) |
4198 | + ow.m.Unlock() |
4199 | + } |
4200 | +} |
4201 | + |
4202 | +func renderCallHeader(label string, c *C, prefix, suffix string) string { |
4203 | + pc := c.method.PC() |
4204 | + return fmt.Sprintf("%s%s: %s: %s%s", prefix, label, niceFuncPath(pc), |
4205 | + niceFuncName(pc), suffix) |
4206 | +} |
4207 | |
4208 | === added file 'internal/gopkg.in/check.v1/check_test.go' |
4209 | --- internal/gopkg.in/check.v1/check_test.go 1970-01-01 00:00:00 +0000 |
4210 | +++ internal/gopkg.in/check.v1/check_test.go 2015-10-30 14:12:15 +0000 |
4211 | @@ -0,0 +1,207 @@ |
4212 | +// This file contains just a few generic helpers which are used by the |
4213 | +// other test files. |
4214 | + |
4215 | +package check_test |
4216 | + |
4217 | +import ( |
4218 | + "flag" |
4219 | + "fmt" |
4220 | + "os" |
4221 | + "regexp" |
4222 | + "runtime" |
4223 | + "testing" |
4224 | + "time" |
4225 | + |
4226 | + "launchpad.net/crackly/internal/gopkg.in/check.v1" |
4227 | +) |
4228 | + |
4229 | +// We count the number of suites run at least to get a vague hint that the |
4230 | +// test suite is behaving as it should. Otherwise a bug introduced at the |
4231 | +// very core of the system could go unperceived. |
4232 | +const suitesRunExpected = 8 |
4233 | + |
4234 | +var suitesRun int = 0 |
4235 | + |
4236 | +func Test(t *testing.T) { |
4237 | + check.TestingT(t) |
4238 | + if suitesRun != suitesRunExpected && flag.Lookup("check.f").Value.String() == "" { |
4239 | + critical(fmt.Sprintf("Expected %d suites to run rather than %d", |
4240 | + suitesRunExpected, suitesRun)) |
4241 | + } |
4242 | +} |
4243 | + |
4244 | +// ----------------------------------------------------------------------- |
4245 | +// Helper functions. |
4246 | + |
4247 | +// Break down badly. This is used in test cases which can't yet assume |
4248 | +// that the fundamental bits are working. |
4249 | +func critical(error string) { |
4250 | + fmt.Fprintln(os.Stderr, "CRITICAL: "+error) |
4251 | + os.Exit(1) |
4252 | +} |
4253 | + |
4254 | +// Return the file line where it's called. |
4255 | +func getMyLine() int { |
4256 | + if _, _, line, ok := runtime.Caller(1); ok { |
4257 | + return line |
4258 | + } |
4259 | + return -1 |
4260 | +} |
4261 | + |
4262 | +// ----------------------------------------------------------------------- |
4263 | +// Helper type implementing a basic io.Writer for testing output. |
4264 | + |
4265 | +// Type implementing the io.Writer interface for analyzing output. |
4266 | +type String struct { |
4267 | + value string |
4268 | +} |
4269 | + |
4270 | +// The only function required by the io.Writer interface. Will append |
4271 | +// written data to the String.value string. |
4272 | +func (s *String) Write(p []byte) (n int, err error) { |
4273 | + s.value += string(p) |
4274 | + return len(p), nil |
4275 | +} |
4276 | + |
4277 | +// Trivial wrapper to test errors happening on a different file |
4278 | +// than the test itself. |
4279 | +func checkEqualWrapper(c *check.C, obtained, expected interface{}) (result bool, line int) { |
4280 | + return c.Check(obtained, check.Equals, expected), getMyLine() |
4281 | +} |
4282 | + |
4283 | +// ----------------------------------------------------------------------- |
4284 | +// Helper suite for testing basic fail behavior. |
4285 | + |
4286 | +type FailHelper struct { |
4287 | + testLine int |
4288 | +} |
4289 | + |
4290 | +func (s *FailHelper) TestLogAndFail(c *check.C) { |
4291 | + s.testLine = getMyLine() - 1 |
4292 | + c.Log("Expected failure!") |
4293 | + c.Fail() |
4294 | +} |
4295 | + |
4296 | +// ----------------------------------------------------------------------- |
4297 | +// Helper suite for testing basic success behavior. |
4298 | + |
4299 | +type SuccessHelper struct{} |
4300 | + |
4301 | +func (s *SuccessHelper) TestLogAndSucceed(c *check.C) { |
4302 | + c.Log("Expected success!") |
4303 | +} |
4304 | + |
4305 | +// ----------------------------------------------------------------------- |
4306 | +// Helper suite for testing ordering and behavior of fixture. |
4307 | + |
4308 | +type FixtureHelper struct { |
4309 | + calls []string |
4310 | + panicOn string |
4311 | + skip bool |
4312 | + skipOnN int |
4313 | + sleepOn string |
4314 | + sleep time.Duration |
4315 | + bytes int64 |
4316 | +} |
4317 | + |
4318 | +func (s *FixtureHelper) trace(name string, c *check.C) { |
4319 | + s.calls = append(s.calls, name) |
4320 | + if name == s.panicOn { |
4321 | + panic(name) |
4322 | + } |
4323 | + if s.sleep > 0 && s.sleepOn == name { |
4324 | + time.Sleep(s.sleep) |
4325 | + } |
4326 | + if s.skip && s.skipOnN == len(s.calls)-1 { |
4327 | + c.Skip("skipOnN == n") |
4328 | + } |
4329 | +} |
4330 | + |
4331 | +func (s *FixtureHelper) SetUpSuite(c *check.C) { |
4332 | + s.trace("SetUpSuite", c) |
4333 | +} |
4334 | + |
4335 | +func (s *FixtureHelper) TearDownSuite(c *check.C) { |
4336 | + s.trace("TearDownSuite", c) |
4337 | +} |
4338 | + |
4339 | +func (s *FixtureHelper) SetUpTest(c *check.C) { |
4340 | + s.trace("SetUpTest", c) |
4341 | +} |
4342 | + |
4343 | +func (s *FixtureHelper) TearDownTest(c *check.C) { |
4344 | + s.trace("TearDownTest", c) |
4345 | +} |
4346 | + |
4347 | +func (s *FixtureHelper) Test1(c *check.C) { |
4348 | + s.trace("Test1", c) |
4349 | +} |
4350 | + |
4351 | +func (s *FixtureHelper) Test2(c *check.C) { |
4352 | + s.trace("Test2", c) |
4353 | +} |
4354 | + |
4355 | +func (s *FixtureHelper) Benchmark1(c *check.C) { |
4356 | + s.trace("Benchmark1", c) |
4357 | + for i := 0; i < c.N; i++ { |
4358 | + time.Sleep(s.sleep) |
4359 | + } |
4360 | +} |
4361 | + |
4362 | +func (s *FixtureHelper) Benchmark2(c *check.C) { |
4363 | + s.trace("Benchmark2", c) |
4364 | + c.SetBytes(1024) |
4365 | + for i := 0; i < c.N; i++ { |
4366 | + time.Sleep(s.sleep) |
4367 | + } |
4368 | +} |
4369 | + |
4370 | +func (s *FixtureHelper) Benchmark3(c *check.C) { |
4371 | + var x []int64 |
4372 | + s.trace("Benchmark3", c) |
4373 | + for i := 0; i < c.N; i++ { |
4374 | + time.Sleep(s.sleep) |
4375 | + x = make([]int64, 5) |
4376 | + _ = x |
4377 | + } |
4378 | +} |
4379 | + |
4380 | +// ----------------------------------------------------------------------- |
4381 | +// Helper which checks the state of the test and ensures that it matches |
4382 | +// the given expectations. Depends on c.Errorf() working, so shouldn't |
4383 | +// be used to test this one function. |
4384 | + |
4385 | +type expectedState struct { |
4386 | + name string |
4387 | + result interface{} |
4388 | + failed bool |
4389 | + log string |
4390 | +} |
4391 | + |
4392 | +// Verify the state of the test. Note that since this also verifies if |
4393 | +// the test is supposed to be in a failed state, no other checks should |
4394 | +// be done in addition to what is being tested. |
4395 | +func checkState(c *check.C, result interface{}, expected *expectedState) { |
4396 | + failed := c.Failed() |
4397 | + c.Succeed() |
4398 | + log := c.GetTestLog() |
4399 | + matched, matchError := regexp.MatchString("^"+expected.log+"$", log) |
4400 | + if matchError != nil { |
4401 | + c.Errorf("Error in matching expression used in testing %s", |
4402 | + expected.name) |
4403 | + } else if !matched { |
4404 | + c.Errorf("%s logged:\n----------\n%s----------\n\nExpected:\n----------\n%s\n----------", |
4405 | + expected.name, log, expected.log) |
4406 | + } |
4407 | + if result != expected.result { |
4408 | + c.Errorf("%s returned %#v rather than %#v", |
4409 | + expected.name, result, expected.result) |
4410 | + } |
4411 | + if failed != expected.failed { |
4412 | + if failed { |
4413 | + c.Errorf("%s has failed when it shouldn't", expected.name) |
4414 | + } else { |
4415 | + c.Errorf("%s has not failed when it should", expected.name) |
4416 | + } |
4417 | + } |
4418 | +} |
4419 | |
4420 | === added file 'internal/gopkg.in/check.v1/checkers.go' |
4421 | --- internal/gopkg.in/check.v1/checkers.go 1970-01-01 00:00:00 +0000 |
4422 | +++ internal/gopkg.in/check.v1/checkers.go 2015-10-30 14:12:15 +0000 |
4423 | @@ -0,0 +1,458 @@ |
4424 | +package check |
4425 | + |
4426 | +import ( |
4427 | + "fmt" |
4428 | + "reflect" |
4429 | + "regexp" |
4430 | +) |
4431 | + |
4432 | +// ----------------------------------------------------------------------- |
4433 | +// CommentInterface and Commentf helper, to attach extra information to checks. |
4434 | + |
4435 | +type comment struct { |
4436 | + format string |
4437 | + args []interface{} |
4438 | +} |
4439 | + |
4440 | +// Commentf returns an infomational value to use with Assert or Check calls. |
4441 | +// If the checker test fails, the provided arguments will be passed to |
4442 | +// fmt.Sprintf, and will be presented next to the logged failure. |
4443 | +// |
4444 | +// For example: |
4445 | +// |
4446 | +// c.Assert(v, Equals, 42, Commentf("Iteration #%d failed.", i)) |
4447 | +// |
4448 | +// Note that if the comment is constant, a better option is to |
4449 | +// simply use a normal comment right above or next to the line, as |
4450 | +// it will also get printed with any errors: |
4451 | +// |
4452 | +// c.Assert(l, Equals, 8192) // Ensure buffer size is correct (bug #123) |
4453 | +// |
4454 | +func Commentf(format string, args ...interface{}) CommentInterface { |
4455 | + return &comment{format, args} |
4456 | +} |
4457 | + |
4458 | +// CommentInterface must be implemented by types that attach extra |
4459 | +// information to failed checks. See the Commentf function for details. |
4460 | +type CommentInterface interface { |
4461 | + CheckCommentString() string |
4462 | +} |
4463 | + |
4464 | +func (c *comment) CheckCommentString() string { |
4465 | + return fmt.Sprintf(c.format, c.args...) |
4466 | +} |
4467 | + |
4468 | +// ----------------------------------------------------------------------- |
4469 | +// The Checker interface. |
4470 | + |
4471 | +// The Checker interface must be provided by checkers used with |
4472 | +// the Assert and Check verification methods. |
4473 | +type Checker interface { |
4474 | + Info() *CheckerInfo |
4475 | + Check(params []interface{}, names []string) (result bool, error string) |
4476 | +} |
4477 | + |
4478 | +// See the Checker interface. |
4479 | +type CheckerInfo struct { |
4480 | + Name string |
4481 | + Params []string |
4482 | +} |
4483 | + |
4484 | +func (info *CheckerInfo) Info() *CheckerInfo { |
4485 | + return info |
4486 | +} |
4487 | + |
4488 | +// ----------------------------------------------------------------------- |
4489 | +// Not checker logic inverter. |
4490 | + |
4491 | +// The Not checker inverts the logic of the provided checker. The |
4492 | +// resulting checker will succeed where the original one failed, and |
4493 | +// vice-versa. |
4494 | +// |
4495 | +// For example: |
4496 | +// |
4497 | +// c.Assert(a, Not(Equals), b) |
4498 | +// |
4499 | +func Not(checker Checker) Checker { |
4500 | + return ¬Checker{checker} |
4501 | +} |
4502 | + |
4503 | +type notChecker struct { |
4504 | + sub Checker |
4505 | +} |
4506 | + |
4507 | +func (checker *notChecker) Info() *CheckerInfo { |
4508 | + info := *checker.sub.Info() |
4509 | + info.Name = "Not(" + info.Name + ")" |
4510 | + return &info |
4511 | +} |
4512 | + |
4513 | +func (checker *notChecker) Check(params []interface{}, names []string) (result bool, error string) { |
4514 | + result, error = checker.sub.Check(params, names) |
4515 | + result = !result |
4516 | + return |
4517 | +} |
4518 | + |
4519 | +// ----------------------------------------------------------------------- |
4520 | +// IsNil checker. |
4521 | + |
4522 | +type isNilChecker struct { |
4523 | + *CheckerInfo |
4524 | +} |
4525 | + |
4526 | +// The IsNil checker tests whether the obtained value is nil. |
4527 | +// |
4528 | +// For example: |
4529 | +// |
4530 | +// c.Assert(err, IsNil) |
4531 | +// |
4532 | +var IsNil Checker = &isNilChecker{ |
4533 | + &CheckerInfo{Name: "IsNil", Params: []string{"value"}}, |
4534 | +} |
4535 | + |
4536 | +func (checker *isNilChecker) Check(params []interface{}, names []string) (result bool, error string) { |
4537 | + return isNil(params[0]), "" |
4538 | +} |
4539 | + |
4540 | +func isNil(obtained interface{}) (result bool) { |
4541 | + if obtained == nil { |
4542 | + result = true |
4543 | + } else { |
4544 | + switch v := reflect.ValueOf(obtained); v.Kind() { |
4545 | + case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: |
4546 | + return v.IsNil() |
4547 | + } |
4548 | + } |
4549 | + return |
4550 | +} |
4551 | + |
4552 | +// ----------------------------------------------------------------------- |
4553 | +// NotNil checker. Alias for Not(IsNil), since it's so common. |
4554 | + |
4555 | +type notNilChecker struct { |
4556 | + *CheckerInfo |
4557 | +} |
4558 | + |
4559 | +// The NotNil checker verifies that the obtained value is not nil. |
4560 | +// |
4561 | +// For example: |
4562 | +// |
4563 | +// c.Assert(iface, NotNil) |
4564 | +// |
4565 | +// This is an alias for Not(IsNil), made available since it's a |
4566 | +// fairly common check. |
4567 | +// |
4568 | +var NotNil Checker = ¬NilChecker{ |
4569 | + &CheckerInfo{Name: "NotNil", Params: []string{"value"}}, |
4570 | +} |
4571 | + |
4572 | +func (checker *notNilChecker) Check(params []interface{}, names []string) (result bool, error string) { |
4573 | + return !isNil(params[0]), "" |
4574 | +} |
4575 | + |
4576 | +// ----------------------------------------------------------------------- |
4577 | +// Equals checker. |
4578 | + |
4579 | +type equalsChecker struct { |
4580 | + *CheckerInfo |
4581 | +} |
4582 | + |
4583 | +// The Equals checker verifies that the obtained value is equal to |
4584 | +// the expected value, according to usual Go semantics for ==. |
4585 | +// |
4586 | +// For example: |
4587 | +// |
4588 | +// c.Assert(value, Equals, 42) |
4589 | +// |
4590 | +var Equals Checker = &equalsChecker{ |
4591 | + &CheckerInfo{Name: "Equals", Params: []string{"obtained", "expected"}}, |
4592 | +} |
4593 | + |
4594 | +func (checker *equalsChecker) Check(params []interface{}, names []string) (result bool, error string) { |
4595 | + defer func() { |
4596 | + if v := recover(); v != nil { |
4597 | + result = false |
4598 | + error = fmt.Sprint(v) |
4599 | + } |
4600 | + }() |
4601 | + return params[0] == params[1], "" |
4602 | +} |
4603 | + |
4604 | +// ----------------------------------------------------------------------- |
4605 | +// DeepEquals checker. |
4606 | + |
4607 | +type deepEqualsChecker struct { |
4608 | + *CheckerInfo |
4609 | +} |
4610 | + |
4611 | +// The DeepEquals checker verifies that the obtained value is deep-equal to |
4612 | +// the expected value. The check will work correctly even when facing |
4613 | +// slices, interfaces, and values of different types (which always fail |
4614 | +// the test). |
4615 | +// |
4616 | +// For example: |
4617 | +// |
4618 | +// c.Assert(value, DeepEquals, 42) |
4619 | +// c.Assert(array, DeepEquals, []string{"hi", "there"}) |
4620 | +// |
4621 | +var DeepEquals Checker = &deepEqualsChecker{ |
4622 | + &CheckerInfo{Name: "DeepEquals", Params: []string{"obtained", "expected"}}, |
4623 | +} |
4624 | + |
4625 | +func (checker *deepEqualsChecker) Check(params []interface{}, names []string) (result bool, error string) { |
4626 | + return reflect.DeepEqual(params[0], params[1]), "" |
4627 | +} |
4628 | + |
4629 | +// ----------------------------------------------------------------------- |
4630 | +// HasLen checker. |
4631 | + |
4632 | +type hasLenChecker struct { |
4633 | + *CheckerInfo |
4634 | +} |
4635 | + |
4636 | +// The HasLen checker verifies that the obtained value has the |
4637 | +// provided length. In many cases this is superior to using Equals |
4638 | +// in conjuction with the len function because in case the check |
4639 | +// fails the value itself will be printed, instead of its length, |
4640 | +// providing more details for figuring the problem. |
4641 | +// |
4642 | +// For example: |
4643 | +// |
4644 | +// c.Assert(list, HasLen, 5) |
4645 | +// |
4646 | +var HasLen Checker = &hasLenChecker{ |
4647 | + &CheckerInfo{Name: "HasLen", Params: []string{"obtained", "n"}}, |
4648 | +} |
4649 | + |
4650 | +func (checker *hasLenChecker) Check(params []interface{}, names []string) (result bool, error string) { |
4651 | + n, ok := params[1].(int) |
4652 | + if !ok { |
4653 | + return false, "n must be an int" |
4654 | + } |
4655 | + value := reflect.ValueOf(params[0]) |
4656 | + switch value.Kind() { |
4657 | + case reflect.Map, reflect.Array, reflect.Slice, reflect.Chan, reflect.String: |
4658 | + default: |
4659 | + return false, "obtained value type has no length" |
4660 | + } |
4661 | + return value.Len() == n, "" |
4662 | +} |
4663 | + |
4664 | +// ----------------------------------------------------------------------- |
4665 | +// ErrorMatches checker. |
4666 | + |
4667 | +type errorMatchesChecker struct { |
4668 | + *CheckerInfo |
4669 | +} |
4670 | + |
4671 | +// The ErrorMatches checker verifies that the error value |
4672 | +// is non nil and matches the regular expression provided. |
4673 | +// |
4674 | +// For example: |
4675 | +// |
4676 | +// c.Assert(err, ErrorMatches, "perm.*denied") |
4677 | +// |
4678 | +var ErrorMatches Checker = errorMatchesChecker{ |
4679 | + &CheckerInfo{Name: "ErrorMatches", Params: []string{"value", "regex"}}, |
4680 | +} |
4681 | + |
4682 | +func (checker errorMatchesChecker) Check(params []interface{}, names []string) (result bool, errStr string) { |
4683 | + if params[0] == nil { |
4684 | + return false, "Error value is nil" |
4685 | + } |
4686 | + err, ok := params[0].(error) |
4687 | + if !ok { |
4688 | + return false, "Value is not an error" |
4689 | + } |
4690 | + params[0] = err.Error() |
4691 | + names[0] = "error" |
4692 | + return matches(params[0], params[1]) |
4693 | +} |
4694 | + |
4695 | +// ----------------------------------------------------------------------- |
4696 | +// Matches checker. |
4697 | + |
4698 | +type matchesChecker struct { |
4699 | + *CheckerInfo |
4700 | +} |
4701 | + |
4702 | +// The Matches checker verifies that the string provided as the obtained |
4703 | +// value (or the string resulting from obtained.String()) matches the |
4704 | +// regular expression provided. |
4705 | +// |
4706 | +// For example: |
4707 | +// |
4708 | +// c.Assert(err, Matches, "perm.*denied") |
4709 | +// |
4710 | +var Matches Checker = &matchesChecker{ |
4711 | + &CheckerInfo{Name: "Matches", Params: []string{"value", "regex"}}, |
4712 | +} |
4713 | + |
4714 | +func (checker *matchesChecker) Check(params []interface{}, names []string) (result bool, error string) { |
4715 | + return matches(params[0], params[1]) |
4716 | +} |
4717 | + |
4718 | +func matches(value, regex interface{}) (result bool, error string) { |
4719 | + reStr, ok := regex.(string) |
4720 | + if !ok { |
4721 | + return false, "Regex must be a string" |
4722 | + } |
4723 | + valueStr, valueIsStr := value.(string) |
4724 | + if !valueIsStr { |
4725 | + if valueWithStr, valueHasStr := value.(fmt.Stringer); valueHasStr { |
4726 | + valueStr, valueIsStr = valueWithStr.String(), true |
4727 | + } |
4728 | + } |
4729 | + if valueIsStr { |
4730 | + matches, err := regexp.MatchString("^"+reStr+"$", valueStr) |
4731 | + if err != nil { |
4732 | + return false, "Can't compile regex: " + err.Error() |
4733 | + } |
4734 | + return matches, "" |
4735 | + } |
4736 | + return false, "Obtained value is not a string and has no .String()" |
4737 | +} |
4738 | + |
4739 | +// ----------------------------------------------------------------------- |
4740 | +// Panics checker. |
4741 | + |
4742 | +type panicsChecker struct { |
4743 | + *CheckerInfo |
4744 | +} |
4745 | + |
4746 | +// The Panics checker verifies that calling the provided zero-argument |
4747 | +// function will cause a panic which is deep-equal to the provided value. |
4748 | +// |
4749 | +// For example: |
4750 | +// |
4751 | +// c.Assert(func() { f(1, 2) }, Panics, &SomeErrorType{"BOOM"}). |
4752 | +// |
4753 | +// |
4754 | +var Panics Checker = &panicsChecker{ |
4755 | + &CheckerInfo{Name: "Panics", Params: []string{"function", "expected"}}, |
4756 | +} |
4757 | + |
4758 | +func (checker *panicsChecker) Check(params []interface{}, names []string) (result bool, error string) { |
4759 | + f := reflect.ValueOf(params[0]) |
4760 | + if f.Kind() != reflect.Func || f.Type().NumIn() != 0 { |
4761 | + return false, "Function must take zero arguments" |
4762 | + } |
4763 | + defer func() { |
4764 | + // If the function has not panicked, then don't do the check. |
4765 | + if error != "" { |
4766 | + return |
4767 | + } |
4768 | + params[0] = recover() |
4769 | + names[0] = "panic" |
4770 | + result = reflect.DeepEqual(params[0], params[1]) |
4771 | + }() |
4772 | + f.Call(nil) |
4773 | + return false, "Function has not panicked" |
4774 | +} |
4775 | + |
4776 | +type panicMatchesChecker struct { |
4777 | + *CheckerInfo |
4778 | +} |
4779 | + |
4780 | +// The PanicMatches checker verifies that calling the provided zero-argument |
4781 | +// function will cause a panic with an error value matching |
4782 | +// the regular expression provided. |
4783 | +// |
4784 | +// For example: |
4785 | +// |
4786 | +// c.Assert(func() { f(1, 2) }, PanicMatches, `open.*: no such file or directory`). |
4787 | +// |
4788 | +// |
4789 | +var PanicMatches Checker = &panicMatchesChecker{ |
4790 | + &CheckerInfo{Name: "PanicMatches", Params: []string{"function", "expected"}}, |
4791 | +} |
4792 | + |
4793 | +func (checker *panicMatchesChecker) Check(params []interface{}, names []string) (result bool, errmsg string) { |
4794 | + f := reflect.ValueOf(params[0]) |
4795 | + if f.Kind() != reflect.Func || f.Type().NumIn() != 0 { |
4796 | + return false, "Function must take zero arguments" |
4797 | + } |
4798 | + defer func() { |
4799 | + // If the function has not panicked, then don't do the check. |
4800 | + if errmsg != "" { |
4801 | + return |
4802 | + } |
4803 | + obtained := recover() |
4804 | + names[0] = "panic" |
4805 | + if e, ok := obtained.(error); ok { |
4806 | + params[0] = e.Error() |
4807 | + } else if _, ok := obtained.(string); ok { |
4808 | + params[0] = obtained |
4809 | + } else { |
4810 | + errmsg = "Panic value is not a string or an error" |
4811 | + return |
4812 | + } |
4813 | + result, errmsg = matches(params[0], params[1]) |
4814 | + }() |
4815 | + f.Call(nil) |
4816 | + return false, "Function has not panicked" |
4817 | +} |
4818 | + |
4819 | +// ----------------------------------------------------------------------- |
4820 | +// FitsTypeOf checker. |
4821 | + |
4822 | +type fitsTypeChecker struct { |
4823 | + *CheckerInfo |
4824 | +} |
4825 | + |
4826 | +// The FitsTypeOf checker verifies that the obtained value is |
4827 | +// assignable to a variable with the same type as the provided |
4828 | +// sample value. |
4829 | +// |
4830 | +// For example: |
4831 | +// |
4832 | +// c.Assert(value, FitsTypeOf, int64(0)) |
4833 | +// c.Assert(value, FitsTypeOf, os.Error(nil)) |
4834 | +// |
4835 | +var FitsTypeOf Checker = &fitsTypeChecker{ |
4836 | + &CheckerInfo{Name: "FitsTypeOf", Params: []string{"obtained", "sample"}}, |
4837 | +} |
4838 | + |
4839 | +func (checker *fitsTypeChecker) Check(params []interface{}, names []string) (result bool, error string) { |
4840 | + obtained := reflect.ValueOf(params[0]) |
4841 | + sample := reflect.ValueOf(params[1]) |
4842 | + if !obtained.IsValid() { |
4843 | + return false, "" |
4844 | + } |
4845 | + if !sample.IsValid() { |
4846 | + return false, "Invalid sample value" |
4847 | + } |
4848 | + return obtained.Type().AssignableTo(sample.Type()), "" |
4849 | +} |
4850 | + |
4851 | +// ----------------------------------------------------------------------- |
4852 | +// Implements checker. |
4853 | + |
4854 | +type implementsChecker struct { |
4855 | + *CheckerInfo |
4856 | +} |
4857 | + |
4858 | +// The Implements checker verifies that the obtained value |
4859 | +// implements the interface specified via a pointer to an interface |
4860 | +// variable. |
4861 | +// |
4862 | +// For example: |
4863 | +// |
4864 | +// var e os.Error |
4865 | +// c.Assert(err, Implements, &e) |
4866 | +// |
4867 | +var Implements Checker = &implementsChecker{ |
4868 | + &CheckerInfo{Name: "Implements", Params: []string{"obtained", "ifaceptr"}}, |
4869 | +} |
4870 | + |
4871 | +func (checker *implementsChecker) Check(params []interface{}, names []string) (result bool, error string) { |
4872 | + obtained := reflect.ValueOf(params[0]) |
4873 | + ifaceptr := reflect.ValueOf(params[1]) |
4874 | + if !obtained.IsValid() { |
4875 | + return false, "" |
4876 | + } |
4877 | + if !ifaceptr.IsValid() || ifaceptr.Kind() != reflect.Ptr || ifaceptr.Elem().Kind() != reflect.Interface { |
4878 | + return false, "ifaceptr should be a pointer to an interface variable" |
4879 | + } |
4880 | + return obtained.Type().Implements(ifaceptr.Elem().Type()), "" |
4881 | +} |
4882 | |
4883 | === added file 'internal/gopkg.in/check.v1/checkers_test.go' |
4884 | --- internal/gopkg.in/check.v1/checkers_test.go 1970-01-01 00:00:00 +0000 |
4885 | +++ internal/gopkg.in/check.v1/checkers_test.go 2015-10-30 14:12:15 +0000 |
4886 | @@ -0,0 +1,272 @@ |
4887 | +package check_test |
4888 | + |
4889 | +import ( |
4890 | + "errors" |
4891 | + "launchpad.net/crackly/internal/gopkg.in/check.v1" |
4892 | + "reflect" |
4893 | + "runtime" |
4894 | +) |
4895 | + |
4896 | +type CheckersS struct{} |
4897 | + |
4898 | +var _ = check.Suite(&CheckersS{}) |
4899 | + |
4900 | +func testInfo(c *check.C, checker check.Checker, name string, paramNames []string) { |
4901 | + info := checker.Info() |
4902 | + if info.Name != name { |
4903 | + c.Fatalf("Got name %s, expected %s", info.Name, name) |
4904 | + } |
4905 | + if !reflect.DeepEqual(info.Params, paramNames) { |
4906 | + c.Fatalf("Got param names %#v, expected %#v", info.Params, paramNames) |
4907 | + } |
4908 | +} |
4909 | + |
4910 | +func testCheck(c *check.C, checker check.Checker, result bool, error string, params ...interface{}) ([]interface{}, []string) { |
4911 | + info := checker.Info() |
4912 | + if len(params) != len(info.Params) { |
4913 | + c.Fatalf("unexpected param count in test; expected %d got %d", len(info.Params), len(params)) |
4914 | + } |
4915 | + names := append([]string{}, info.Params...) |
4916 | + result_, error_ := checker.Check(params, names) |
4917 | + if result_ != result || error_ != error { |
4918 | + c.Fatalf("%s.Check(%#v) returned (%#v, %#v) rather than (%#v, %#v)", |
4919 | + info.Name, params, result_, error_, result, error) |
4920 | + } |
4921 | + return params, names |
4922 | +} |
4923 | + |
4924 | +func (s *CheckersS) TestComment(c *check.C) { |
4925 | + bug := check.Commentf("a %d bc", 42) |
4926 | + comment := bug.CheckCommentString() |
4927 | + if comment != "a 42 bc" { |
4928 | + c.Fatalf("Commentf returned %#v", comment) |
4929 | + } |
4930 | +} |
4931 | + |
4932 | +func (s *CheckersS) TestIsNil(c *check.C) { |
4933 | + testInfo(c, check.IsNil, "IsNil", []string{"value"}) |
4934 | + |
4935 | + testCheck(c, check.IsNil, true, "", nil) |
4936 | + testCheck(c, check.IsNil, false, "", "a") |
4937 | + |
4938 | + testCheck(c, check.IsNil, true, "", (chan int)(nil)) |
4939 | + testCheck(c, check.IsNil, false, "", make(chan int)) |
4940 | + testCheck(c, check.IsNil, true, "", (error)(nil)) |
4941 | + testCheck(c, check.IsNil, false, "", errors.New("")) |
4942 | + testCheck(c, check.IsNil, true, "", ([]int)(nil)) |
4943 | + testCheck(c, check.IsNil, false, "", make([]int, 1)) |
4944 | + testCheck(c, check.IsNil, false, "", int(0)) |
4945 | +} |
4946 | + |
4947 | +func (s *CheckersS) TestNotNil(c *check.C) { |
4948 | + testInfo(c, check.NotNil, "NotNil", []string{"value"}) |
4949 | + |
4950 | + testCheck(c, check.NotNil, false, "", nil) |
4951 | + testCheck(c, check.NotNil, true, "", "a") |
4952 | + |
4953 | + testCheck(c, check.NotNil, false, "", (chan int)(nil)) |
4954 | + testCheck(c, check.NotNil, true, "", make(chan int)) |
4955 | + testCheck(c, check.NotNil, false, "", (error)(nil)) |
4956 | + testCheck(c, check.NotNil, true, "", errors.New("")) |
4957 | + testCheck(c, check.NotNil, false, "", ([]int)(nil)) |
4958 | + testCheck(c, check.NotNil, true, "", make([]int, 1)) |
4959 | +} |
4960 | + |
4961 | +func (s *CheckersS) TestNot(c *check.C) { |
4962 | + testInfo(c, check.Not(check.IsNil), "Not(IsNil)", []string{"value"}) |
4963 | + |
4964 | + testCheck(c, check.Not(check.IsNil), false, "", nil) |
4965 | + testCheck(c, check.Not(check.IsNil), true, "", "a") |
4966 | +} |
4967 | + |
4968 | +type simpleStruct struct { |
4969 | + i int |
4970 | +} |
4971 | + |
4972 | +func (s *CheckersS) TestEquals(c *check.C) { |
4973 | + testInfo(c, check.Equals, "Equals", []string{"obtained", "expected"}) |
4974 | + |
4975 | + // The simplest. |
4976 | + testCheck(c, check.Equals, true, "", 42, 42) |
4977 | + testCheck(c, check.Equals, false, "", 42, 43) |
4978 | + |
4979 | + // Different native types. |
4980 | + testCheck(c, check.Equals, false, "", int32(42), int64(42)) |
4981 | + |
4982 | + // With nil. |
4983 | + testCheck(c, check.Equals, false, "", 42, nil) |
4984 | + |
4985 | + // Slices |
4986 | + testCheck(c, check.Equals, false, "runtime error: comparing uncomparable type []uint8", []byte{1, 2}, []byte{1, 2}) |
4987 | + |
4988 | + // Struct values |
4989 | + testCheck(c, check.Equals, true, "", simpleStruct{1}, simpleStruct{1}) |
4990 | + testCheck(c, check.Equals, false, "", simpleStruct{1}, simpleStruct{2}) |
4991 | + |
4992 | + // Struct pointers |
4993 | + testCheck(c, check.Equals, false, "", &simpleStruct{1}, &simpleStruct{1}) |
4994 | + testCheck(c, check.Equals, false, "", &simpleStruct{1}, &simpleStruct{2}) |
4995 | +} |
4996 | + |
4997 | +func (s *CheckersS) TestDeepEquals(c *check.C) { |
4998 | + testInfo(c, check.DeepEquals, "DeepEquals", []string{"obtained", "expected"}) |
4999 | + |
5000 | + // The simplest. |
The diff has been truncated for viewing.