aboutsummaryrefslogtreecommitdiffstats
path: root/Godeps/_workspace/src/github.com
diff options
context:
space:
mode:
authorPéter Szilágyi <peterke@gmail.com>2016-02-11 22:16:52 +0800
committerPéter Szilágyi <peterke@gmail.com>2016-02-11 22:16:52 +0800
commitb019f3ee29ce55c3d515ee8bafe0f4bb14221c0a (patch)
tree26e023be6c99a10e82a5a0ebadd1e42cefe9bd3c /Godeps/_workspace/src/github.com
parentb05e472c076d30035233d6a8b5fb3360b236e3ff (diff)
downloaddexon-b019f3ee29ce55c3d515ee8bafe0f4bb14221c0a.tar
dexon-b019f3ee29ce55c3d515ee8bafe0f4bb14221c0a.tar.gz
dexon-b019f3ee29ce55c3d515ee8bafe0f4bb14221c0a.tar.bz2
dexon-b019f3ee29ce55c3d515ee8bafe0f4bb14221c0a.tar.lz
dexon-b019f3ee29ce55c3d515ee8bafe0f4bb14221c0a.tar.xz
dexon-b019f3ee29ce55c3d515ee8bafe0f4bb14221c0a.tar.zst
dexon-b019f3ee29ce55c3d515ee8bafe0f4bb14221c0a.zip
Godeps: update all dependencies to latest code
Diffstat (limited to 'Godeps/_workspace/src/github.com')
-rw-r--r--Godeps/_workspace/src/github.com/Gustav-Simonsson/go-opencl/cl/cl_test.go254
-rw-r--r--Godeps/_workspace/src/github.com/codegangsta/cli/.travis.yml6
-rw-r--r--Godeps/_workspace/src/github.com/codegangsta/cli/README.md43
-rw-r--r--Godeps/_workspace/src/github.com/codegangsta/cli/app.go62
-rw-r--r--Godeps/_workspace/src/github.com/codegangsta/cli/appveyor.yml16
-rw-r--r--Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/bash_autocomplete5
-rw-r--r--Godeps/_workspace/src/github.com/codegangsta/cli/command.go108
-rw-r--r--Godeps/_workspace/src/github.com/codegangsta/cli/context.go6
-rw-r--r--Godeps/_workspace/src/github.com/codegangsta/cli/flag.go135
-rw-r--r--Godeps/_workspace/src/github.com/codegangsta/cli/help.go6
-rw-r--r--Godeps/_workspace/src/github.com/davecgh/go-spew/LICENSE13
-rw-r--r--Godeps/_workspace/src/github.com/davecgh/go-spew/spew/bypass.go151
-rw-r--r--Godeps/_workspace/src/github.com/davecgh/go-spew/spew/bypasssafe.go37
-rw-r--r--Godeps/_workspace/src/github.com/davecgh/go-spew/spew/common.go135
-rw-r--r--Godeps/_workspace/src/github.com/davecgh/go-spew/spew/common_test.go298
-rw-r--r--Godeps/_workspace/src/github.com/davecgh/go-spew/spew/config.go5
-rw-r--r--Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dump.go31
-rw-r--r--Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dump_test.go1021
-rw-r--r--Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dumpcgo_test.go97
-rw-r--r--Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dumpnocgo_test.go26
-rw-r--r--Godeps/_workspace/src/github.com/davecgh/go-spew/spew/example_test.go230
-rw-r--r--Godeps/_workspace/src/github.com/davecgh/go-spew/spew/format_test.go1535
-rw-r--r--Godeps/_workspace/src/github.com/davecgh/go-spew/spew/internal_test.go156
-rw-r--r--Godeps/_workspace/src/github.com/davecgh/go-spew/spew/spew_test.go308
-rw-r--r--Godeps/_workspace/src/github.com/davecgh/go-spew/spew/testdata/dumpcgo.go82
-rw-r--r--Godeps/_workspace/src/github.com/ethereum/ethash/ethash_test.go221
-rw-r--r--Godeps/_workspace/src/github.com/fatih/color/color.go53
-rw-r--r--Godeps/_workspace/src/github.com/fatih/color/color_test.go176
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/.gitignore1
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/README.md169
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/barchart.go (renamed from Godeps/_workspace/src/github.com/gizak/termui/bar.go)67
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/block.go286
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/block_common.go (renamed from Godeps/_workspace/src/github.com/gizak/termui/box_others.go)8
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/block_test.go46
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/block_windows.go (renamed from Godeps/_workspace/src/github.com/gizak/termui/box_windows.go)2
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/box.go117
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/buffer.go106
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/canvas.go12
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/canvas_test.go55
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/config26
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/debug/debuger.go117
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/doc.go2
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/events.go455
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/events_test.go28
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/example/barchart.go35
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/example/barchart.pngbin15386 -> 0 bytes
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/example/dashboard.gifbin453764 -> 0 bytes
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/example/dashboard.go148
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/example/gauge.go62
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/example/gauge.pngbin32431 -> 0 bytes
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/example/grid.gifbin800288 -> 0 bytes
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/example/grid.go134
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/example/linechart.go68
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/example/linechart.pngbin139361 -> 0 bytes
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/example/list.go41
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/example/list.pngbin37227 -> 0 bytes
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/example/mbarchart.go50
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/example/mbarchart.pngbin20075 -> 0 bytes
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/example/par.go48
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/example/par.pngbin65773 -> 0 bytes
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/example/sparklines.go65
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/example/sparklines.pngbin43431 -> 0 bytes
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/example/theme.go143
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/example/themedefault.pngbin105508 -> 0 bytes
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/example/themehelloworld.pngbin90111 -> 0 bytes
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/gauge.go90
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/grid.go20
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/grid_test.go98
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/helper.go156
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/helper_test.go58
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/linechart.go (renamed from Godeps/_workspace/src/github.com/gizak/termui/chart.go)153
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/linechart_others.go (renamed from Godeps/_workspace/src/github.com/gizak/termui/chart_others.go)2
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/linechart_windows.go (renamed from Godeps/_workspace/src/github.com/gizak/termui/chart_windows.go)2
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/list.go53
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/mbarchart.go (renamed from Godeps/_workspace/src/github.com/gizak/termui/mbar.go)103
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/p.go71
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/par.go64
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/point.go28
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/pos.go78
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/render.go117
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/sparkline.go83
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/test/runtest.go66
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/textbuilder.go215
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/theme.go58
-rw-r--r--Godeps/_workspace/src/github.com/gizak/termui/widget.go94
-rw-r--r--Godeps/_workspace/src/github.com/golang/snappy/AUTHORS15
-rw-r--r--Godeps/_workspace/src/github.com/golang/snappy/CONTRIBUTORS37
-rw-r--r--Godeps/_workspace/src/github.com/golang/snappy/LICENSE27
-rw-r--r--Godeps/_workspace/src/github.com/golang/snappy/README7
-rw-r--r--Godeps/_workspace/src/github.com/golang/snappy/decode.go (renamed from Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/decode.go)30
-rw-r--r--Godeps/_workspace/src/github.com/golang/snappy/encode.go (renamed from Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/encode.go)192
-rw-r--r--Godeps/_workspace/src/github.com/golang/snappy/snappy.go (renamed from Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/snappy.go)15
-rw-r--r--Godeps/_workspace/src/github.com/hashicorp/golang-lru/2q.go212
-rw-r--r--Godeps/_workspace/src/github.com/hashicorp/golang-lru/arc.go257
-rw-r--r--Godeps/_workspace/src/github.com/hashicorp/golang-lru/lru.go147
-rw-r--r--Godeps/_workspace/src/github.com/hashicorp/golang-lru/lru_test.go127
-rw-r--r--Godeps/_workspace/src/github.com/hashicorp/golang-lru/simplelru/lru.go160
-rw-r--r--Godeps/_workspace/src/github.com/jackpal/gateway/LICENSE27
-rw-r--r--Godeps/_workspace/src/github.com/jackpal/gateway/README.md7
-rw-r--r--Godeps/_workspace/src/github.com/jackpal/gateway/gateway_darwin.go40
-rw-r--r--Godeps/_workspace/src/github.com/jackpal/gateway/gateway_linux.go75
-rw-r--r--Godeps/_workspace/src/github.com/jackpal/gateway/gateway_unimplemented.go14
-rw-r--r--Godeps/_workspace/src/github.com/jackpal/gateway/gateway_windows.go43
-rw-r--r--Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/natpmp.go12
-rw-r--r--Godeps/_workspace/src/github.com/mattn/go-colorable/LICENSE (renamed from Godeps/_workspace/src/github.com/shiena/ansicolor/LICENSE)2
-rw-r--r--Godeps/_workspace/src/github.com/mattn/go-colorable/README.md43
-rw-r--r--Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_others.go16
-rw-r--r--Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_windows.go782
-rw-r--r--Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_appengine.go9
-rw-r--r--Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_bsd.go1
-rw-r--r--Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_linux.go1
-rw-r--r--Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_solaris.go16
-rw-r--r--Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_windows.go1
-rw-r--r--Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth.go70
-rw-r--r--Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_test.go134
-rw-r--r--Godeps/_workspace/src/github.com/nsf/termbox-go/README.md2
-rw-r--r--Godeps/_workspace/src/github.com/nsf/termbox-go/api.go2
-rw-r--r--Godeps/_workspace/src/github.com/nsf/termbox-go/api_common.go6
-rw-r--r--Godeps/_workspace/src/github.com/nsf/termbox-go/api_windows.go6
-rw-r--r--Godeps/_workspace/src/github.com/nsf/termbox-go/termbox.go127
-rw-r--r--Godeps/_workspace/src/github.com/nsf/termbox-go/termbox_windows.go65
-rw-r--r--Godeps/_workspace/src/github.com/nsf/termbox-go/terminfo.go6
-rw-r--r--Godeps/_workspace/src/github.com/nsf/termbox-go/terminfo_builtin.go8
-rw-r--r--Godeps/_workspace/src/github.com/pborman/uuid/.travis.yml10
-rw-r--r--Godeps/_workspace/src/github.com/pborman/uuid/README.md13
-rw-r--r--Godeps/_workspace/src/github.com/pborman/uuid/hash.go2
-rw-r--r--Godeps/_workspace/src/github.com/pborman/uuid/json.go12
-rw-r--r--Godeps/_workspace/src/github.com/pborman/uuid/json_test.go32
-rw-r--r--Godeps/_workspace/src/github.com/pborman/uuid/node.go20
-rw-r--r--Godeps/_workspace/src/github.com/pborman/uuid/seq_test.go66
-rw-r--r--Godeps/_workspace/src/github.com/pborman/uuid/sql.go36
-rw-r--r--Godeps/_workspace/src/github.com/pborman/uuid/sql_test.go53
-rw-r--r--Godeps/_workspace/src/github.com/pborman/uuid/time.go14
-rw-r--r--Godeps/_workspace/src/github.com/pborman/uuid/util.go2
-rw-r--r--Godeps/_workspace/src/github.com/pborman/uuid/uuid.go39
-rw-r--r--Godeps/_workspace/src/github.com/pborman/uuid/uuid_test.go390
-rw-r--r--Godeps/_workspace/src/github.com/peterh/liner/README.md17
-rw-r--r--Godeps/_workspace/src/github.com/peterh/liner/common.go26
-rw-r--r--Godeps/_workspace/src/github.com/peterh/liner/input.go17
-rw-r--r--Godeps/_workspace/src/github.com/peterh/liner/input_test.go61
-rw-r--r--Godeps/_workspace/src/github.com/peterh/liner/input_windows.go8
-rw-r--r--Godeps/_workspace/src/github.com/peterh/liner/line.go228
-rw-r--r--Godeps/_workspace/src/github.com/peterh/liner/line_test.go90
-rw-r--r--Godeps/_workspace/src/github.com/peterh/liner/output.go12
-rw-r--r--Godeps/_workspace/src/github.com/peterh/liner/output_windows.go18
-rw-r--r--Godeps/_workspace/src/github.com/peterh/liner/prefix_test.go37
-rw-r--r--Godeps/_workspace/src/github.com/peterh/liner/race_test.go44
-rw-r--r--Godeps/_workspace/src/github.com/peterh/liner/width.go34
-rw-r--r--Godeps/_workspace/src/github.com/peterh/liner/width_test.go87
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/.travis.yml14
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/README.md49
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/counter_test.go77
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/debug_test.go48
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/ewma.go2
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/ewma_test.go225
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/exp/exp.go148
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/gauge_float64_test.go38
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/gauge_test.go37
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/graphite.go2
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/graphite_test.go22
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/histogram_test.go95
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/influxdb/influxdb.go114
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/json.go2
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/json_test.go28
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/librato/librato.go7
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/log.go31
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/meter_test.go60
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/metrics_test.go107
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/opentsdb_test.go22
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/registry.go67
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/registry_test.go118
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime.go56
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime_gccpufraction.go9
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime_no_gccpufraction.go9
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime_test.go78
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/sample_test.go363
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/timer_test.go81
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/validate.sh10
-rw-r--r--Godeps/_workspace/src/github.com/rcrowley/go-metrics/writer_test.go22
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/README.markdown8
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/array_test.go716
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/bug_test.go617
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_array.go2
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_test.go136
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/clone.go18
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate_expression.go8
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate_statement.go3
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_test.go54
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/date_test.go481
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/dbg/dbg.go2
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/documentation_test.go95
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/error_test.go192
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/function_test.go280
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/global_test.go355
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/json_test.go183
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/math_test.go303
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/number_test.go165
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/object_test.go639
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/otto.go91
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/otto_.go4
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/otto_error_test.go48
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/otto_test.go1379
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/panic_test.go40
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/parser/expression.go2
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/parser/lexer_test.go380
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/parser/marshal_test.go930
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/parser/parser.go3
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/parser/parser_test.go1004
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/parser/regexp_test.go149
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/parser_test.go42
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/reflect_test.go483
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/regexp_test.go290
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/repl/repl.go115
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/runtime.go213
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/runtime_test.go778
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/script_test.go78
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/stash.go21
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/string_test.go365
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/testing_test.go135
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/type_function.go11
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/type_go_map.go2
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/underscore/source.go1
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_arrays_test.go344
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_chaining_test.go95
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_collections_test.go698
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_functions_test.go208
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_objects_test.go826
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_test.go165
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_utility_test.go419
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/value.go44
-rw-r--r--Godeps/_workspace/src/github.com/robertkrimen/otto/value_test.go281
-rw-r--r--Godeps/_workspace/src/github.com/shiena/ansicolor/.gitignore27
-rw-r--r--Godeps/_workspace/src/github.com/shiena/ansicolor/README.md100
-rw-r--r--Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor.go20
-rw-r--r--Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor/main.go27
-rw-r--r--Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_ansi.go17
-rw-r--r--Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_test.go25
-rw-r--r--Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_windows.go351
-rw-r--r--Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_windows_test.go236
-rw-r--r--Godeps/_workspace/src/github.com/shiena/ansicolor/example_test.go24
-rw-r--r--Godeps/_workspace/src/github.com/shiena/ansicolor/export_test.go19
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/LICENSE24
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/batch.go26
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/batch_test.go120
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/bench2_test.go58
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/bench_test.go464
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/bench2_test.go30
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/cache_test.go554
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/corrupt_test.go500
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db.go596
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_compaction.go281
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_iter.go42
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_snapshot.go8
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_state.go68
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_test.go2665
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_transaction.go289
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_util.go50
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_write.go113
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors.go1
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors/errors.go24
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/external_test.go58
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter/bloom_test.go142
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/array_iter_test.go30
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/indexed_iter_test.go83
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/iter_suite_test.go11
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/merged_iter_test.go60
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/journal/journal.go3
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/journal/journal_test.go818
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/key.go17
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/key_test.go133
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/leveldb_suite_test.go11
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/bench_test.go75
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb.go9
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb_suite_test.go11
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb_test.go135
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt/options.go91
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/options.go41
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session.go312
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_compaction.go302
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_record.go74
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_record_test.go64
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_util.go113
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage.go565
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_plan9.go17
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_solaris.go25
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_test.go142
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_unix.go37
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_windows.go17
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/mem_storage.go207
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/mem_storage_test.go66
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/storage.go154
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage_test.go539
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table.go85
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/block_test.go139
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/reader.go12
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/table_suite_test.go11
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/table_test.go122
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/writer.go8
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/kvtest.go206
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/storage.go468
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil_test.go63
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util.go14
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/buffer_pool.go1
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/buffer_test.go369
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/version.go258
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/gosnappy/LICENSE27
-rw-r--r--Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/snappy_test.go364
307 files changed, 8847 insertions, 33488 deletions
diff --git a/Godeps/_workspace/src/github.com/Gustav-Simonsson/go-opencl/cl/cl_test.go b/Godeps/_workspace/src/github.com/Gustav-Simonsson/go-opencl/cl/cl_test.go
deleted file mode 100644
index 7659ce14f..000000000
--- a/Godeps/_workspace/src/github.com/Gustav-Simonsson/go-opencl/cl/cl_test.go
+++ /dev/null
@@ -1,254 +0,0 @@
-package cl
-
-import (
- "math/rand"
- "reflect"
- "strings"
- "testing"
-)
-
-var kernelSource = `
-__kernel void square(
- __global float* input,
- __global float* output,
- const unsigned int count)
-{
- int i = get_global_id(0);
- if(i < count)
- output[i] = input[i] * input[i];
-}
-`
-
-func getObjectStrings(object interface{}) map[string]string {
- v := reflect.ValueOf(object)
- t := reflect.TypeOf(object)
-
- strs := make(map[string]string)
-
- numMethods := t.NumMethod()
- for i := 0; i < numMethods; i++ {
- method := t.Method(i)
- if method.Type.NumIn() == 1 && method.Type.NumOut() == 1 && method.Type.Out(0).Kind() == reflect.String {
- // this is a string-returning method with (presumably) only a pointer receiver parameter
- // call it
- outs := v.Method(i).Call([]reflect.Value{})
- // put the result in our map
- strs[method.Name] = (outs[0].Interface()).(string)
- }
- }
-
- return strs
-}
-
-func TestPlatformStringsContainNoNULs(t *testing.T) {
- platforms, err := GetPlatforms()
- if err != nil {
- t.Fatalf("Failed to get platforms: %+v", err)
- }
-
- for _, p := range platforms {
- for key, value := range getObjectStrings(p) {
- if strings.Contains(value, "\x00") {
- t.Fatalf("platform string %q = %+q contains NUL", key, value)
- }
- }
- }
-}
-
-func TestDeviceStringsContainNoNULs(t *testing.T) {
- platforms, err := GetPlatforms()
- if err != nil {
- t.Fatalf("Failed to get platforms: %+v", err)
- }
-
- for _, p := range platforms {
- devs, err := p.GetDevices(DeviceTypeAll)
- if err != nil {
- t.Fatalf("Failed to get devices for platform %q: %+v", p.Name(), err)
- }
-
- for _, d := range devs {
- for key, value := range getObjectStrings(d) {
- if strings.Contains(value, "\x00") {
- t.Fatalf("device string %q = %+q contains NUL", key, value)
- }
- }
- }
- }
-}
-
-func TestHello(t *testing.T) {
- var data [1024]float32
- for i := 0; i < len(data); i++ {
- data[i] = rand.Float32()
- }
-
- platforms, err := GetPlatforms()
- if err != nil {
- t.Fatalf("Failed to get platforms: %+v", err)
- }
- for i, p := range platforms {
- t.Logf("Platform %d:", i)
- t.Logf(" Name: %s", p.Name())
- t.Logf(" Vendor: %s", p.Vendor())
- t.Logf(" Profile: %s", p.Profile())
- t.Logf(" Version: %s", p.Version())
- t.Logf(" Extensions: %s", p.Extensions())
- }
- platform := platforms[0]
-
- devices, err := platform.GetDevices(DeviceTypeAll)
- if err != nil {
- t.Fatalf("Failed to get devices: %+v", err)
- }
- if len(devices) == 0 {
- t.Fatalf("GetDevices returned no devices")
- }
- deviceIndex := -1
- for i, d := range devices {
- if deviceIndex < 0 && d.Type() == DeviceTypeGPU {
- deviceIndex = i
- }
- t.Logf("Device %d (%s): %s", i, d.Type(), d.Name())
- t.Logf(" Address Bits: %d", d.AddressBits())
- t.Logf(" Available: %+v", d.Available())
- // t.Logf(" Built-In Kernels: %s", d.BuiltInKernels())
- t.Logf(" Compiler Available: %+v", d.CompilerAvailable())
- t.Logf(" Double FP Config: %s", d.DoubleFPConfig())
- t.Logf(" Driver Version: %s", d.DriverVersion())
- t.Logf(" Error Correction Supported: %+v", d.ErrorCorrectionSupport())
- t.Logf(" Execution Capabilities: %s", d.ExecutionCapabilities())
- t.Logf(" Extensions: %s", d.Extensions())
- t.Logf(" Global Memory Cache Type: %s", d.GlobalMemCacheType())
- t.Logf(" Global Memory Cacheline Size: %d KB", d.GlobalMemCachelineSize()/1024)
- t.Logf(" Global Memory Size: %d MB", d.GlobalMemSize()/(1024*1024))
- t.Logf(" Half FP Config: %s", d.HalfFPConfig())
- t.Logf(" Host Unified Memory: %+v", d.HostUnifiedMemory())
- t.Logf(" Image Support: %+v", d.ImageSupport())
- t.Logf(" Image2D Max Dimensions: %d x %d", d.Image2DMaxWidth(), d.Image2DMaxHeight())
- t.Logf(" Image3D Max Dimenionns: %d x %d x %d", d.Image3DMaxWidth(), d.Image3DMaxHeight(), d.Image3DMaxDepth())
- // t.Logf(" Image Max Buffer Size: %d", d.ImageMaxBufferSize())
- // t.Logf(" Image Max Array Size: %d", d.ImageMaxArraySize())
- // t.Logf(" Linker Available: %+v", d.LinkerAvailable())
- t.Logf(" Little Endian: %+v", d.EndianLittle())
- t.Logf(" Local Mem Size Size: %d KB", d.LocalMemSize()/1024)
- t.Logf(" Local Mem Type: %s", d.LocalMemType())
- t.Logf(" Max Clock Frequency: %d", d.MaxClockFrequency())
- t.Logf(" Max Compute Units: %d", d.MaxComputeUnits())
- t.Logf(" Max Constant Args: %d", d.MaxConstantArgs())
- t.Logf(" Max Constant Buffer Size: %d KB", d.MaxConstantBufferSize()/1024)
- t.Logf(" Max Mem Alloc Size: %d KB", d.MaxMemAllocSize()/1024)
- t.Logf(" Max Parameter Size: %d", d.MaxParameterSize())
- t.Logf(" Max Read-Image Args: %d", d.MaxReadImageArgs())
- t.Logf(" Max Samplers: %d", d.MaxSamplers())
- t.Logf(" Max Work Group Size: %d", d.MaxWorkGroupSize())
- t.Logf(" Max Work Item Dimensions: %d", d.MaxWorkItemDimensions())
- t.Logf(" Max Work Item Sizes: %d", d.MaxWorkItemSizes())
- t.Logf(" Max Write-Image Args: %d", d.MaxWriteImageArgs())
- t.Logf(" Memory Base Address Alignment: %d", d.MemBaseAddrAlign())
- t.Logf(" Native Vector Width Char: %d", d.NativeVectorWidthChar())
- t.Logf(" Native Vector Width Short: %d", d.NativeVectorWidthShort())
- t.Logf(" Native Vector Width Int: %d", d.NativeVectorWidthInt())
- t.Logf(" Native Vector Width Long: %d", d.NativeVectorWidthLong())
- t.Logf(" Native Vector Width Float: %d", d.NativeVectorWidthFloat())
- t.Logf(" Native Vector Width Double: %d", d.NativeVectorWidthDouble())
- t.Logf(" Native Vector Width Half: %d", d.NativeVectorWidthHalf())
- t.Logf(" OpenCL C Version: %s", d.OpenCLCVersion())
- // t.Logf(" Parent Device: %+v", d.ParentDevice())
- t.Logf(" Profile: %s", d.Profile())
- t.Logf(" Profiling Timer Resolution: %d", d.ProfilingTimerResolution())
- t.Logf(" Vendor: %s", d.Vendor())
- t.Logf(" Version: %s", d.Version())
- }
- if deviceIndex < 0 {
- deviceIndex = 0
- }
- device := devices[deviceIndex]
- t.Logf("Using device %d", deviceIndex)
- context, err := CreateContext([]*Device{device})
- if err != nil {
- t.Fatalf("CreateContext failed: %+v", err)
- }
- // imageFormats, err := context.GetSupportedImageFormats(0, MemObjectTypeImage2D)
- // if err != nil {
- // t.Fatalf("GetSupportedImageFormats failed: %+v", err)
- // }
- // t.Logf("Supported image formats: %+v", imageFormats)
- queue, err := context.CreateCommandQueue(device, 0)
- if err != nil {
- t.Fatalf("CreateCommandQueue failed: %+v", err)
- }
- program, err := context.CreateProgramWithSource([]string{kernelSource})
- if err != nil {
- t.Fatalf("CreateProgramWithSource failed: %+v", err)
- }
- if err := program.BuildProgram(nil, ""); err != nil {
- t.Fatalf("BuildProgram failed: %+v", err)
- }
- kernel, err := program.CreateKernel("square")
- if err != nil {
- t.Fatalf("CreateKernel failed: %+v", err)
- }
- for i := 0; i < 3; i++ {
- name, err := kernel.ArgName(i)
- if err == ErrUnsupported {
- break
- } else if err != nil {
- t.Errorf("GetKernelArgInfo for name failed: %+v", err)
- break
- } else {
- t.Logf("Kernel arg %d: %s", i, name)
- }
- }
- input, err := context.CreateEmptyBuffer(MemReadOnly, 4*len(data))
- if err != nil {
- t.Fatalf("CreateBuffer failed for input: %+v", err)
- }
- output, err := context.CreateEmptyBuffer(MemReadOnly, 4*len(data))
- if err != nil {
- t.Fatalf("CreateBuffer failed for output: %+v", err)
- }
- if _, err := queue.EnqueueWriteBufferFloat32(input, true, 0, data[:], nil); err != nil {
- t.Fatalf("EnqueueWriteBufferFloat32 failed: %+v", err)
- }
- if err := kernel.SetArgs(input, output, uint32(len(data))); err != nil {
- t.Fatalf("SetKernelArgs failed: %+v", err)
- }
-
- local, err := kernel.WorkGroupSize(device)
- if err != nil {
- t.Fatalf("WorkGroupSize failed: %+v", err)
- }
- t.Logf("Work group size: %d", local)
- size, _ := kernel.PreferredWorkGroupSizeMultiple(nil)
- t.Logf("Preferred Work Group Size Multiple: %d", size)
-
- global := len(data)
- d := len(data) % local
- if d != 0 {
- global += local - d
- }
- if _, err := queue.EnqueueNDRangeKernel(kernel, nil, []int{global}, []int{local}, nil); err != nil {
- t.Fatalf("EnqueueNDRangeKernel failed: %+v", err)
- }
-
- if err := queue.Finish(); err != nil {
- t.Fatalf("Finish failed: %+v", err)
- }
-
- results := make([]float32, len(data))
- if _, err := queue.EnqueueReadBufferFloat32(output, true, 0, results, nil); err != nil {
- t.Fatalf("EnqueueReadBufferFloat32 failed: %+v", err)
- }
-
- correct := 0
- for i, v := range data {
- if results[i] == v*v {
- correct++
- }
- }
-
- if correct != len(data) {
- t.Fatalf("%d/%d correct values", correct, len(data))
- }
-}
diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/.travis.yml b/Godeps/_workspace/src/github.com/codegangsta/cli/.travis.yml
index 34d39c871..87ba52f98 100644
--- a/Godeps/_workspace/src/github.com/codegangsta/cli/.travis.yml
+++ b/Godeps/_workspace/src/github.com/codegangsta/cli/.travis.yml
@@ -7,6 +7,12 @@ go:
- 1.2.2
- 1.3.3
- 1.4.2
+- 1.5.1
+- tip
+
+matrix:
+ allow_failures:
+ - go: tip
script:
- go vet ./...
diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/README.md b/Godeps/_workspace/src/github.com/codegangsta/cli/README.md
index 234655710..ae0a4ca3a 100644
--- a/Godeps/_workspace/src/github.com/codegangsta/cli/README.md
+++ b/Godeps/_workspace/src/github.com/codegangsta/cli/README.md
@@ -1,16 +1,19 @@
[![Coverage](http://gocover.io/_badge/github.com/codegangsta/cli?0)](http://gocover.io/github.com/codegangsta/cli)
-[![Build Status](https://travis-ci.org/codegangsta/cli.png?branch=master)](https://travis-ci.org/codegangsta/cli)
+[![Build Status](https://travis-ci.org/codegangsta/cli.svg?branch=master)](https://travis-ci.org/codegangsta/cli)
[![GoDoc](https://godoc.org/github.com/codegangsta/cli?status.svg)](https://godoc.org/github.com/codegangsta/cli)
# cli.go
+
`cli.go` is simple, fast, and fun package for building command line apps in Go. The goal is to enable developers to write fast and distributable command line applications in an expressive way.
## Overview
+
Command line apps are usually so tiny that there is absolutely no reason why your code should *not* be self-documenting. Things like generating help text and parsing command flags/options should not hinder productivity when writing a command line app.
**This is where `cli.go` comes into play.** `cli.go` makes command line programming fun, organized, and expressive!
## Installation
+
Make sure you have a working Go environment (go 1.1+ is *required*). [See the install instructions](http://golang.org/doc/install.html).
To install `cli.go`, simply run:
@@ -24,6 +27,7 @@ export PATH=$PATH:$GOPATH/bin
```
## Getting Started
+
One of the philosophies behind `cli.go` is that an API should be playful and full of discovery. So a `cli.go` app can be as little as one line of code in `main()`.
``` go
@@ -123,6 +127,7 @@ GLOBAL OPTIONS
```
### Arguments
+
You can lookup arguments by calling the `Args` function on `cli.Context`.
``` go
@@ -134,7 +139,9 @@ app.Action = func(c *cli.Context) {
```
### Flags
+
Setting and querying flags is simple.
+
``` go
...
app.Flags = []cli.Flag {
@@ -158,6 +165,33 @@ app.Action = func(c *cli.Context) {
...
```
+You can also set a destination variable for a flag, to which the content will be scanned.
+
+``` go
+...
+var language string
+app.Flags = []cli.Flag {
+ cli.StringFlag{
+ Name: "lang",
+ Value: "english",
+ Usage: "language for the greeting",
+ Destination: &language,
+ },
+}
+app.Action = func(c *cli.Context) {
+ name := "someone"
+ if len(c.Args()) > 0 {
+ name = c.Args()[0]
+ }
+ if language == "spanish" {
+ println("Hola", name)
+ } else {
+ println("Hello", name)
+ }
+}
+...
+```
+
See full list of flags at http://godoc.org/github.com/codegangsta/cli
#### Alternate Names
@@ -207,6 +241,7 @@ app.Flags = []cli.Flag {
### Subcommands
Subcommands can be defined for a more git-like command line app.
+
```go
...
app.Commands = []cli.Command{
@@ -257,6 +292,7 @@ You can enable completion commands by setting the `EnableBashCompletion`
flag on the `App` object. By default, this setting will only auto-complete to
show an app's subcommands, but you can write your own completion methods for
the App or its subcommands.
+
```go
...
var tasks = []string{"cook", "clean", "laundry", "eat", "sleep", "code"}
@@ -299,8 +335,8 @@ automatically install it there if you are distributing a package). Don't forget
to source the file to make it active in the current shell.
```
- sudo cp src/bash_autocomplete /etc/bash_completion.d/<myprogram>
- source /etc/bash_completion.d/<myprogram>
+sudo cp src/bash_autocomplete /etc/bash_completion.d/<myprogram>
+source /etc/bash_completion.d/<myprogram>
```
Alternatively, you can just document that users should source the generic
@@ -308,6 +344,7 @@ Alternatively, you can just document that users should source the generic
to the name of their program (as above).
## Contribution Guidelines
+
Feel free to put up a pull request to fix a bug or maybe add a feature. I will give it a code review and make sure that it does not break backwards compatibility. If I or any other collaborators agree that it is in line with the vision of the project, we will work with you to get the code into a mergeable state and merge it into the master branch.
If you have contributed something significant to the project, I will most likely add you as a collaborator. As a collaborator you are given the ability to merge others pull requests. It is very important that new code does not break existing code, so be careful about what code you do choose to merge. If you have any questions feel free to link @codegangsta to the issue in question and we can review it together.
diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/app.go b/Godeps/_workspace/src/github.com/codegangsta/cli/app.go
index 9a15c0c03..1ea3fd0b1 100644
--- a/Godeps/_workspace/src/github.com/codegangsta/cli/app.go
+++ b/Godeps/_workspace/src/github.com/codegangsta/cli/app.go
@@ -5,18 +5,21 @@ import (
"io"
"io/ioutil"
"os"
+ "path"
"time"
)
-// App is the main structure of a cli application. It is recomended that
+// App is the main structure of a cli application. It is recommended that
// an app be created with the cli.NewApp() function
type App struct {
- // The name of the program. Defaults to os.Args[0]
+ // The name of the program. Defaults to path.Base(os.Args[0])
Name string
// Full name of command for help, defaults to Name
HelpName string
// Description of the program.
Usage string
+ // Text to override the USAGE section of help
+ UsageText string
// Description of the program argument format.
ArgsUsage string
// Version of the program
@@ -43,6 +46,10 @@ type App struct {
Action func(context *Context)
// Execute this function if the proper command cannot be found
CommandNotFound func(context *Context, command string)
+ // Execute this function, if an usage error occurs. This is useful for displaying customized usage error messages.
+ // This function is able to replace the original error messages.
+ // If this function is not set, the "Incorrect usage" is displayed and the execution is interrupted.
+ OnUsageError func(context *Context, err error, isSubcommand bool) error
// Compilation date
Compiled time.Time
// List of all authors who contributed
@@ -70,9 +77,10 @@ func compileTime() time.Time {
// Creates a new cli Application with some reasonable defaults for Name, Usage, Version and Action.
func NewApp() *App {
return &App{
- Name: os.Args[0],
- HelpName: os.Args[0],
+ Name: path.Base(os.Args[0]),
+ HelpName: path.Base(os.Args[0]),
Usage: "A new cli application",
+ UsageText: "",
Version: "0.0.0",
BashComplete: DefaultAppComplete,
Action: helpCommand.Action,
@@ -118,25 +126,28 @@ func (a *App) Run(arguments []string) (err error) {
set.SetOutput(ioutil.Discard)
err = set.Parse(arguments[1:])
nerr := normalizeFlags(a.Flags, set)
+ context := NewContext(a, set, nil)
if nerr != nil {
fmt.Fprintln(a.Writer, nerr)
- context := NewContext(a, set, nil)
ShowAppHelp(context)
return nerr
}
- context := NewContext(a, set, nil)
-
- if err != nil {
- fmt.Fprintln(a.Writer, "Incorrect Usage.")
- fmt.Fprintln(a.Writer)
- ShowAppHelp(context)
- return err
- }
if checkCompletions(context) {
return nil
}
+ if err != nil {
+ if a.OnUsageError != nil {
+ err := a.OnUsageError(context, err, false)
+ return err
+ } else {
+ fmt.Fprintf(a.Writer, "%s\n\n", "Incorrect Usage.")
+ ShowAppHelp(context)
+ return err
+ }
+ }
+
if !a.HideHelp && checkHelp(context) {
ShowAppHelp(context)
return nil
@@ -149,8 +160,7 @@ func (a *App) Run(arguments []string) (err error) {
if a.After != nil {
defer func() {
- afterErr := a.After(context)
- if afterErr != nil {
+ if afterErr := a.After(context); afterErr != nil {
if err != nil {
err = NewMultiError(err, afterErr)
} else {
@@ -161,8 +171,10 @@ func (a *App) Run(arguments []string) (err error) {
}
if a.Before != nil {
- err := a.Before(context)
+ err = a.Before(context)
if err != nil {
+ fmt.Fprintf(a.Writer, "%v\n\n", err)
+ ShowAppHelp(context)
return err
}
}
@@ -233,17 +245,21 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
return nerr
}
- if err != nil {
- fmt.Fprintln(a.Writer, "Incorrect Usage.")
- fmt.Fprintln(a.Writer)
- ShowSubcommandHelp(context)
- return err
- }
-
if checkCompletions(context) {
return nil
}
+ if err != nil {
+ if a.OnUsageError != nil {
+ err = a.OnUsageError(context, err, true)
+ return err
+ } else {
+ fmt.Fprintf(a.Writer, "%s\n\n", "Incorrect Usage.")
+ ShowSubcommandHelp(context)
+ return err
+ }
+ }
+
if len(a.Commands) > 0 {
if checkSubcommandHelp(context) {
return nil
diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/appveyor.yml b/Godeps/_workspace/src/github.com/codegangsta/cli/appveyor.yml
new file mode 100644
index 000000000..3ca7afabd
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/codegangsta/cli/appveyor.yml
@@ -0,0 +1,16 @@
+version: "{build}"
+
+os: Windows Server 2012 R2
+
+install:
+ - go version
+ - go env
+
+build_script:
+ - cd %APPVEYOR_BUILD_FOLDER%
+ - go vet ./...
+ - go test -v ./...
+
+test: off
+
+deploy: off
diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/bash_autocomplete b/Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/bash_autocomplete
index d9231f4cf..21a232f1f 100644
--- a/Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/bash_autocomplete
+++ b/Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/bash_autocomplete
@@ -3,13 +3,12 @@
: ${PROG:=$(basename ${BASH_SOURCE})}
_cli_bash_autocomplete() {
- local cur prev opts base
+ local cur opts base
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
- prev="${COMP_WORDS[COMP_CWORD-1]}"
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion )
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
}
- complete -F _cli_bash_autocomplete $PROG \ No newline at end of file
+ complete -F _cli_bash_autocomplete $PROG
diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/command.go b/Godeps/_workspace/src/github.com/codegangsta/cli/command.go
index fac754deb..bbf42ae40 100644
--- a/Godeps/_workspace/src/github.com/codegangsta/cli/command.go
+++ b/Godeps/_workspace/src/github.com/codegangsta/cli/command.go
@@ -16,6 +16,8 @@ type Command struct {
Aliases []string
// A short description of the usage of this command
Usage string
+ // Custom text to show on USAGE section of help
+ UsageText string
// A longer explanation of how the command works
Description string
// A short description of the arguments of this command
@@ -30,6 +32,10 @@ type Command struct {
After func(context *Context) error
// The function to call when this command is invoked
Action func(context *Context)
+ // Execute this function, if an usage error occurs. This is useful for displaying customized usage error messages.
+ // This function is able to replace the original error messages.
+ // If this function is not set, the "Incorrect usage" is displayed and the execution is interrupted.
+ OnUsageError func(context *Context, err error) error
// List of child commands
Subcommands []Command
// List of flags to parse
@@ -54,8 +60,8 @@ func (c Command) FullName() string {
}
// Invokes the command given the context, parses ctx.Args() to generate command-specific flags
-func (c Command) Run(ctx *Context) error {
- if len(c.Subcommands) > 0 || c.Before != nil || c.After != nil {
+func (c Command) Run(ctx *Context) (err error) {
+ if len(c.Subcommands) > 0 {
return c.startApp(ctx)
}
@@ -74,41 +80,54 @@ func (c Command) Run(ctx *Context) error {
set := flagSet(c.Name, c.Flags)
set.SetOutput(ioutil.Discard)
- firstFlagIndex := -1
- terminatorIndex := -1
- for index, arg := range ctx.Args() {
- if arg == "--" {
- terminatorIndex = index
- break
- } else if strings.HasPrefix(arg, "-") && firstFlagIndex == -1 {
- firstFlagIndex = index
+ if !c.SkipFlagParsing {
+ firstFlagIndex := -1
+ terminatorIndex := -1
+ for index, arg := range ctx.Args() {
+ if arg == "--" {
+ terminatorIndex = index
+ break
+ } else if arg == "-" {
+ // Do nothing. A dash alone is not really a flag.
+ continue
+ } else if strings.HasPrefix(arg, "-") && firstFlagIndex == -1 {
+ firstFlagIndex = index
+ }
}
- }
- var err error
- if firstFlagIndex > -1 && !c.SkipFlagParsing {
- args := ctx.Args()
- regularArgs := make([]string, len(args[1:firstFlagIndex]))
- copy(regularArgs, args[1:firstFlagIndex])
+ if firstFlagIndex > -1 {
+ args := ctx.Args()
+ regularArgs := make([]string, len(args[1:firstFlagIndex]))
+ copy(regularArgs, args[1:firstFlagIndex])
+
+ var flagArgs []string
+ if terminatorIndex > -1 {
+ flagArgs = args[firstFlagIndex:terminatorIndex]
+ regularArgs = append(regularArgs, args[terminatorIndex:]...)
+ } else {
+ flagArgs = args[firstFlagIndex:]
+ }
- var flagArgs []string
- if terminatorIndex > -1 {
- flagArgs = args[firstFlagIndex:terminatorIndex]
- regularArgs = append(regularArgs, args[terminatorIndex:]...)
+ err = set.Parse(append(flagArgs, regularArgs...))
} else {
- flagArgs = args[firstFlagIndex:]
+ err = set.Parse(ctx.Args().Tail())
}
-
- err = set.Parse(append(flagArgs, regularArgs...))
} else {
- err = set.Parse(ctx.Args().Tail())
+ if c.SkipFlagParsing {
+ err = set.Parse(append([]string{"--"}, ctx.Args().Tail()...))
+ }
}
if err != nil {
- fmt.Fprintln(ctx.App.Writer, "Incorrect Usage.")
- fmt.Fprintln(ctx.App.Writer)
- ShowCommandHelp(ctx, c.Name)
- return err
+ if c.OnUsageError != nil {
+ err := c.OnUsageError(ctx, err)
+ return err
+ } else {
+ fmt.Fprintln(ctx.App.Writer, "Incorrect Usage.")
+ fmt.Fprintln(ctx.App.Writer)
+ ShowCommandHelp(ctx, c.Name)
+ return err
+ }
}
nerr := normalizeFlags(c.Flags, set)
@@ -127,6 +146,30 @@ func (c Command) Run(ctx *Context) error {
if checkCommandHelp(context, c.Name) {
return nil
}
+
+ if c.After != nil {
+ defer func() {
+ afterErr := c.After(context)
+ if afterErr != nil {
+ if err != nil {
+ err = NewMultiError(err, afterErr)
+ } else {
+ err = afterErr
+ }
+ }
+ }()
+ }
+
+ if c.Before != nil {
+ err := c.Before(context)
+ if err != nil {
+ fmt.Fprintln(ctx.App.Writer, err)
+ fmt.Fprintln(ctx.App.Writer)
+ ShowCommandHelp(ctx, c.Name)
+ return err
+ }
+ }
+
context.Command = c
c.Action(context)
return nil
@@ -160,7 +203,7 @@ func (c Command) startApp(ctx *Context) error {
if c.HelpName == "" {
app.HelpName = c.HelpName
} else {
- app.HelpName = fmt.Sprintf("%s %s", ctx.App.Name, c.Name)
+ app.HelpName = app.Name
}
if c.Description != "" {
@@ -199,12 +242,9 @@ func (c Command) startApp(ctx *Context) error {
app.Action = helpSubcommand.Action
}
- var newCmds []Command
- for _, cc := range app.Commands {
- cc.commandNamePath = []string{c.Name, cc.Name}
- newCmds = append(newCmds, cc)
+ for index, cc := range app.Commands {
+ app.Commands[index].commandNamePath = []string{c.Name, cc.Name}
}
- app.Commands = newCmds
return app.RunAsSubcommand(ctx)
}
diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/context.go b/Godeps/_workspace/src/github.com/codegangsta/cli/context.go
index f541f41c3..0513d34f6 100644
--- a/Godeps/_workspace/src/github.com/codegangsta/cli/context.go
+++ b/Godeps/_workspace/src/github.com/codegangsta/cli/context.go
@@ -163,7 +163,7 @@ func (c *Context) GlobalIsSet(name string) bool {
// Returns a slice of flag names used in this context.
func (c *Context) FlagNames() (names []string) {
for _, flag := range c.Command.Flags {
- name := strings.Split(flag.getName(), ",")[0]
+ name := strings.Split(flag.GetName(), ",")[0]
if name == "help" {
continue
}
@@ -175,7 +175,7 @@ func (c *Context) FlagNames() (names []string) {
// Returns a slice of global flag names used by the app.
func (c *Context) GlobalFlagNames() (names []string) {
for _, flag := range c.App.Flags {
- name := strings.Split(flag.getName(), ",")[0]
+ name := strings.Split(flag.GetName(), ",")[0]
if name == "help" || name == "version" {
continue
}
@@ -360,7 +360,7 @@ func normalizeFlags(flags []Flag, set *flag.FlagSet) error {
visited[f.Name] = true
})
for _, f := range flags {
- parts := strings.Split(f.getName(), ",")
+ parts := strings.Split(f.GetName(), ",")
if len(parts) == 1 {
continue
}
diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/flag.go b/Godeps/_workspace/src/github.com/codegangsta/cli/flag.go
index 531b09130..e951c2df7 100644
--- a/Godeps/_workspace/src/github.com/codegangsta/cli/flag.go
+++ b/Godeps/_workspace/src/github.com/codegangsta/cli/flag.go
@@ -4,6 +4,7 @@ import (
"flag"
"fmt"
"os"
+ "runtime"
"strconv"
"strings"
"time"
@@ -29,13 +30,13 @@ var HelpFlag = BoolFlag{
}
// Flag is a common interface related to parsing flags in cli.
-// For more advanced flag parsing techniques, it is recomended that
+// For more advanced flag parsing techniques, it is recommended that
// this interface be implemented.
type Flag interface {
fmt.Stringer
// Apply Flag settings to the given flag set
Apply(*flag.FlagSet)
- getName() string
+ GetName() string
}
func flagSet(name string, flags []Flag) *flag.FlagSet {
@@ -73,7 +74,18 @@ type GenericFlag struct {
// help text to the user (uses the String() method of the generic flag to show
// the value)
func (f GenericFlag) String() string {
- return withEnvHint(f.EnvVar, fmt.Sprintf("%s%s \"%v\"\t%v", prefixFor(f.Name), f.Name, f.Value, f.Usage))
+ return withEnvHint(f.EnvVar, fmt.Sprintf("%s %v\t%v", prefixedNames(f.Name), f.FormatValueHelp(), f.Usage))
+}
+
+func (f GenericFlag) FormatValueHelp() string {
+ if f.Value == nil {
+ return ""
+ }
+ s := f.Value.String()
+ if len(s) == 0 {
+ return ""
+ }
+ return fmt.Sprintf("\"%s\"", s)
}
// Apply takes the flagset and calls Set on the generic flag with the value
@@ -95,7 +107,7 @@ func (f GenericFlag) Apply(set *flag.FlagSet) {
})
}
-func (f GenericFlag) getName() string {
+func (f GenericFlag) GetName() string {
return f.Name
}
@@ -159,7 +171,7 @@ func (f StringSliceFlag) Apply(set *flag.FlagSet) {
})
}
-func (f StringSliceFlag) getName() string {
+func (f StringSliceFlag) GetName() string {
return f.Name
}
@@ -231,15 +243,16 @@ func (f IntSliceFlag) Apply(set *flag.FlagSet) {
})
}
-func (f IntSliceFlag) getName() string {
+func (f IntSliceFlag) GetName() string {
return f.Name
}
// BoolFlag is a switch that defaults to false
type BoolFlag struct {
- Name string
- Usage string
- EnvVar string
+ Name string
+ Usage string
+ EnvVar string
+ Destination *bool
}
// String returns a readable representation of this value (for usage defaults)
@@ -264,20 +277,25 @@ func (f BoolFlag) Apply(set *flag.FlagSet) {
}
eachName(f.Name, func(name string) {
+ if f.Destination != nil {
+ set.BoolVar(f.Destination, name, val, f.Usage)
+ return
+ }
set.Bool(name, val, f.Usage)
})
}
-func (f BoolFlag) getName() string {
+func (f BoolFlag) GetName() string {
return f.Name
}
// BoolTFlag this represents a boolean flag that is true by default, but can
// still be set to false by --some-flag=false
type BoolTFlag struct {
- Name string
- Usage string
- EnvVar string
+ Name string
+ Usage string
+ EnvVar string
+ Destination *bool
}
// String returns a readable representation of this value (for usage defaults)
@@ -302,34 +320,38 @@ func (f BoolTFlag) Apply(set *flag.FlagSet) {
}
eachName(f.Name, func(name string) {
+ if f.Destination != nil {
+ set.BoolVar(f.Destination, name, val, f.Usage)
+ return
+ }
set.Bool(name, val, f.Usage)
})
}
-func (f BoolTFlag) getName() string {
+func (f BoolTFlag) GetName() string {
return f.Name
}
// StringFlag represents a flag that takes as string value
type StringFlag struct {
- Name string
- Value string
- Usage string
- EnvVar string
+ Name string
+ Value string
+ Usage string
+ EnvVar string
+ Destination *string
}
// String returns the usage
func (f StringFlag) String() string {
- var fmtString string
- fmtString = "%s %v\t%v"
+ return withEnvHint(f.EnvVar, fmt.Sprintf("%s %v\t%v", prefixedNames(f.Name), f.FormatValueHelp(), f.Usage))
+}
- if len(f.Value) > 0 {
- fmtString = "%s \"%v\"\t%v"
- } else {
- fmtString = "%s %v\t%v"
+func (f StringFlag) FormatValueHelp() string {
+ s := f.Value
+ if len(s) == 0 {
+ return ""
}
-
- return withEnvHint(f.EnvVar, fmt.Sprintf(fmtString, prefixedNames(f.Name), f.Value, f.Usage))
+ return fmt.Sprintf("\"%s\"", s)
}
// Apply populates the flag given the flag set and environment
@@ -345,21 +367,26 @@ func (f StringFlag) Apply(set *flag.FlagSet) {
}
eachName(f.Name, func(name string) {
+ if f.Destination != nil {
+ set.StringVar(f.Destination, name, f.Value, f.Usage)
+ return
+ }
set.String(name, f.Value, f.Usage)
})
}
-func (f StringFlag) getName() string {
+func (f StringFlag) GetName() string {
return f.Name
}
// IntFlag is a flag that takes an integer
// Errors if the value provided cannot be parsed
type IntFlag struct {
- Name string
- Value int
- Usage string
- EnvVar string
+ Name string
+ Value int
+ Usage string
+ EnvVar string
+ Destination *int
}
// String returns the usage
@@ -383,21 +410,26 @@ func (f IntFlag) Apply(set *flag.FlagSet) {
}
eachName(f.Name, func(name string) {
+ if f.Destination != nil {
+ set.IntVar(f.Destination, name, f.Value, f.Usage)
+ return
+ }
set.Int(name, f.Value, f.Usage)
})
}
-func (f IntFlag) getName() string {
+func (f IntFlag) GetName() string {
return f.Name
}
// DurationFlag is a flag that takes a duration specified in Go's duration
// format: https://golang.org/pkg/time/#ParseDuration
type DurationFlag struct {
- Name string
- Value time.Duration
- Usage string
- EnvVar string
+ Name string
+ Value time.Duration
+ Usage string
+ EnvVar string
+ Destination *time.Duration
}
// String returns a readable representation of this value (for usage defaults)
@@ -421,21 +453,26 @@ func (f DurationFlag) Apply(set *flag.FlagSet) {
}
eachName(f.Name, func(name string) {
+ if f.Destination != nil {
+ set.DurationVar(f.Destination, name, f.Value, f.Usage)
+ return
+ }
set.Duration(name, f.Value, f.Usage)
})
}
-func (f DurationFlag) getName() string {
+func (f DurationFlag) GetName() string {
return f.Name
}
// Float64Flag is a flag that takes an float value
// Errors if the value provided cannot be parsed
type Float64Flag struct {
- Name string
- Value float64
- Usage string
- EnvVar string
+ Name string
+ Value float64
+ Usage string
+ EnvVar string
+ Destination *float64
}
// String returns the usage
@@ -458,11 +495,15 @@ func (f Float64Flag) Apply(set *flag.FlagSet) {
}
eachName(f.Name, func(name string) {
+ if f.Destination != nil {
+ set.Float64Var(f.Destination, name, f.Value, f.Usage)
+ return
+ }
set.Float64(name, f.Value, f.Usage)
})
}
-func (f Float64Flag) getName() string {
+func (f Float64Flag) GetName() string {
return f.Name
}
@@ -491,7 +532,15 @@ func prefixedNames(fullName string) (prefixed string) {
func withEnvHint(envVar, str string) string {
envText := ""
if envVar != "" {
- envText = fmt.Sprintf(" [$%s]", strings.Join(strings.Split(envVar, ","), ", $"))
+ prefix := "$"
+ suffix := ""
+ sep := ", $"
+ if runtime.GOOS == "windows" {
+ prefix = "%"
+ suffix = "%"
+ sep = "%, %"
+ }
+ envText = fmt.Sprintf(" [%s%s%s]", prefix, strings.Join(strings.Split(envVar, ","), sep), suffix)
}
return str + envText
}
diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/help.go b/Godeps/_workspace/src/github.com/codegangsta/cli/help.go
index a246f63ac..15916f86a 100644
--- a/Godeps/_workspace/src/github.com/codegangsta/cli/help.go
+++ b/Godeps/_workspace/src/github.com/codegangsta/cli/help.go
@@ -15,7 +15,7 @@ var AppHelpTemplate = `NAME:
{{.Name}} - {{.Usage}}
USAGE:
- {{.HelpName}} {{if .Flags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}
+ {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} {{if .Flags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}
{{if .Version}}
VERSION:
{{.Version}}
@@ -180,7 +180,9 @@ func printHelp(out io.Writer, templ string, data interface{}) {
t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
err := t.Execute(w, data)
if err != nil {
- panic(err)
+ // If the writer is closed, t.Execute will fail, and there's nothing
+ // we can do to recover. We could send this to os.Stderr if we need.
+ return
}
w.Flush()
}
diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/LICENSE b/Godeps/_workspace/src/github.com/davecgh/go-spew/LICENSE
new file mode 100644
index 000000000..2a7cfd2bf
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/LICENSE
@@ -0,0 +1,13 @@
+Copyright (c) 2012-2013 Dave Collins <dave@davec.name>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/bypass.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/bypass.go
new file mode 100644
index 000000000..565bf5899
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/bypass.go
@@ -0,0 +1,151 @@
+// Copyright (c) 2015 Dave Collins <dave@davec.name>
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+// NOTE: Due to the following build constraints, this file will only be compiled
+// when the code is not running on Google App Engine and "-tags disableunsafe"
+// is not added to the go build command line.
+// +build !appengine,!disableunsafe
+
+package spew
+
+import (
+ "reflect"
+ "unsafe"
+)
+
+const (
+ // UnsafeDisabled is a build-time constant which specifies whether or
+ // not access to the unsafe package is available.
+ UnsafeDisabled = false
+
+ // ptrSize is the size of a pointer on the current arch.
+ ptrSize = unsafe.Sizeof((*byte)(nil))
+)
+
+var (
+ // offsetPtr, offsetScalar, and offsetFlag are the offsets for the
+ // internal reflect.Value fields. These values are valid before golang
+ // commit ecccf07e7f9d which changed the format. The are also valid
+ // after commit 82f48826c6c7 which changed the format again to mirror
+ // the original format. Code in the init function updates these offsets
+ // as necessary.
+ offsetPtr = uintptr(ptrSize)
+ offsetScalar = uintptr(0)
+ offsetFlag = uintptr(ptrSize * 2)
+
+ // flagKindWidth and flagKindShift indicate various bits that the
+ // reflect package uses internally to track kind information.
+ //
+ // flagRO indicates whether or not the value field of a reflect.Value is
+ // read-only.
+ //
+ // flagIndir indicates whether the value field of a reflect.Value is
+ // the actual data or a pointer to the data.
+ //
+ // These values are valid before golang commit 90a7c3c86944 which
+ // changed their positions. Code in the init function updates these
+ // flags as necessary.
+ flagKindWidth = uintptr(5)
+ flagKindShift = uintptr(flagKindWidth - 1)
+ flagRO = uintptr(1 << 0)
+ flagIndir = uintptr(1 << 1)
+)
+
+func init() {
+ // Older versions of reflect.Value stored small integers directly in the
+ // ptr field (which is named val in the older versions). Versions
+ // between commits ecccf07e7f9d and 82f48826c6c7 added a new field named
+ // scalar for this purpose which unfortunately came before the flag
+ // field, so the offset of the flag field is different for those
+ // versions.
+ //
+ // This code constructs a new reflect.Value from a known small integer
+ // and checks if the size of the reflect.Value struct indicates it has
+ // the scalar field. When it does, the offsets are updated accordingly.
+ vv := reflect.ValueOf(0xf00)
+ if unsafe.Sizeof(vv) == (ptrSize * 4) {
+ offsetScalar = ptrSize * 2
+ offsetFlag = ptrSize * 3
+ }
+
+ // Commit 90a7c3c86944 changed the flag positions such that the low
+ // order bits are the kind. This code extracts the kind from the flags
+ // field and ensures it's the correct type. When it's not, the flag
+ // order has been changed to the newer format, so the flags are updated
+ // accordingly.
+ upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag)
+ upfv := *(*uintptr)(upf)
+ flagKindMask := uintptr((1<<flagKindWidth - 1) << flagKindShift)
+ if (upfv&flagKindMask)>>flagKindShift != uintptr(reflect.Int) {
+ flagKindShift = 0
+ flagRO = 1 << 5
+ flagIndir = 1 << 6
+
+ // Commit adf9b30e5594 modified the flags to separate the
+ // flagRO flag into two bits which specifies whether or not the
+ // field is embedded. This causes flagIndir to move over a bit
+ // and means that flagRO is the combination of either of the
+ // original flagRO bit and the new bit.
+ //
+ // This code detects the change by extracting what used to be
+ // the indirect bit to ensure it's set. When it's not, the flag
+ // order has been changed to the newer format, so the flags are
+ // updated accordingly.
+ if upfv&flagIndir == 0 {
+ flagRO = 3 << 5
+ flagIndir = 1 << 7
+ }
+ }
+}
+
+// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
+// the typical safety restrictions preventing access to unaddressable and
+// unexported data. It works by digging the raw pointer to the underlying
+// value out of the protected value and generating a new unprotected (unsafe)
+// reflect.Value to it.
+//
+// This allows us to check for implementations of the Stringer and error
+// interfaces to be used for pretty printing ordinarily unaddressable and
+// inaccessible values such as unexported struct fields.
+func unsafeReflectValue(v reflect.Value) (rv reflect.Value) {
+ indirects := 1
+ vt := v.Type()
+ upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr)
+ rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag))
+ if rvf&flagIndir != 0 {
+ vt = reflect.PtrTo(v.Type())
+ indirects++
+ } else if offsetScalar != 0 {
+ // The value is in the scalar field when it's not one of the
+ // reference types.
+ switch vt.Kind() {
+ case reflect.Uintptr:
+ case reflect.Chan:
+ case reflect.Func:
+ case reflect.Map:
+ case reflect.Ptr:
+ case reflect.UnsafePointer:
+ default:
+ upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) +
+ offsetScalar)
+ }
+ }
+
+ pv := reflect.NewAt(vt, upv)
+ rv = pv
+ for i := 0; i < indirects; i++ {
+ rv = rv.Elem()
+ }
+ return rv
+}
diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/bypasssafe.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/bypasssafe.go
new file mode 100644
index 000000000..457e41235
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/bypasssafe.go
@@ -0,0 +1,37 @@
+// Copyright (c) 2015 Dave Collins <dave@davec.name>
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+// NOTE: Due to the following build constraints, this file will only be compiled
+// when either the code is running on Google App Engine or "-tags disableunsafe"
+// is added to the go build command line.
+// +build appengine disableunsafe
+
+package spew
+
+import "reflect"
+
+const (
+ // UnsafeDisabled is a build-time constant which specifies whether or
+ // not access to the unsafe package is available.
+ UnsafeDisabled = true
+)
+
+// unsafeReflectValue typically converts the passed reflect.Value into a one
+// that bypasses the typical safety restrictions preventing access to
+// unaddressable and unexported data. However, doing this relies on access to
+// the unsafe package. This is a stub version which simply returns the passed
+// reflect.Value when the unsafe package is not available.
+func unsafeReflectValue(v reflect.Value) reflect.Value {
+ return v
+}
diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/common.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/common.go
index 8252cd3ee..14f02dc15 100644
--- a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/common.go
+++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/common.go
@@ -23,116 +23,8 @@ import (
"reflect"
"sort"
"strconv"
- "unsafe"
)
-const (
- // ptrSize is the size of a pointer on the current arch.
- ptrSize = unsafe.Sizeof((*byte)(nil))
-)
-
-var (
- // offsetPtr, offsetScalar, and offsetFlag are the offsets for the
- // internal reflect.Value fields. These values are valid before golang
- // commit ecccf07e7f9d which changed the format. The are also valid
- // after commit 82f48826c6c7 which changed the format again to mirror
- // the original format. Code in the init function updates these offsets
- // as necessary.
- offsetPtr = uintptr(ptrSize)
- offsetScalar = uintptr(0)
- offsetFlag = uintptr(ptrSize * 2)
-
- // flagKindWidth and flagKindShift indicate various bits that the
- // reflect package uses internally to track kind information.
- //
- // flagRO indicates whether or not the value field of a reflect.Value is
- // read-only.
- //
- // flagIndir indicates whether the value field of a reflect.Value is
- // the actual data or a pointer to the data.
- //
- // These values are valid before golang commit 90a7c3c86944 which
- // changed their positions. Code in the init function updates these
- // flags as necessary.
- flagKindWidth = uintptr(5)
- flagKindShift = uintptr(flagKindWidth - 1)
- flagRO = uintptr(1 << 0)
- flagIndir = uintptr(1 << 1)
-)
-
-func init() {
- // Older versions of reflect.Value stored small integers directly in the
- // ptr field (which is named val in the older versions). Versions
- // between commits ecccf07e7f9d and 82f48826c6c7 added a new field named
- // scalar for this purpose which unfortunately came before the flag
- // field, so the offset of the flag field is different for those
- // versions.
- //
- // This code constructs a new reflect.Value from a known small integer
- // and checks if the size of the reflect.Value struct indicates it has
- // the scalar field. When it does, the offsets are updated accordingly.
- vv := reflect.ValueOf(0xf00)
- if unsafe.Sizeof(vv) == (ptrSize * 4) {
- offsetScalar = ptrSize * 2
- offsetFlag = ptrSize * 3
- }
-
- // Commit 90a7c3c86944 changed the flag positions such that the low
- // order bits are the kind. This code extracts the kind from the flags
- // field and ensures it's the correct type. When it's not, the flag
- // order has been changed to the newer format, so the flags are updated
- // accordingly.
- upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag)
- upfv := *(*uintptr)(upf)
- flagKindMask := uintptr((1<<flagKindWidth - 1) << flagKindShift)
- if (upfv&flagKindMask)>>flagKindShift != uintptr(reflect.Int) {
- flagKindShift = 0
- flagRO = 1 << 5
- flagIndir = 1 << 6
- }
-}
-
-// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
-// the typical safety restrictions preventing access to unaddressable and
-// unexported data. It works by digging the raw pointer to the underlying
-// value out of the protected value and generating a new unprotected (unsafe)
-// reflect.Value to it.
-//
-// This allows us to check for implementations of the Stringer and error
-// interfaces to be used for pretty printing ordinarily unaddressable and
-// inaccessible values such as unexported struct fields.
-func unsafeReflectValue(v reflect.Value) (rv reflect.Value) {
- indirects := 1
- vt := v.Type()
- upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr)
- rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag))
- if rvf&flagIndir != 0 {
- vt = reflect.PtrTo(v.Type())
- indirects++
- } else if offsetScalar != 0 {
- // The value is in the scalar field when it's not one of the
- // reference types.
- switch vt.Kind() {
- case reflect.Uintptr:
- case reflect.Chan:
- case reflect.Func:
- case reflect.Map:
- case reflect.Ptr:
- case reflect.UnsafePointer:
- default:
- upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) +
- offsetScalar)
- }
- }
-
- pv := reflect.NewAt(vt, upv)
- rv = pv
- for i := 0; i < indirects; i++ {
- rv = rv.Elem()
- }
- return rv
-}
-
// Some constants in the form of bytes to avoid string overhead. This mirrors
// the technique used in the fmt package.
var (
@@ -194,9 +86,14 @@ func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool)
// We need an interface to check if the type implements the error or
// Stringer interface. However, the reflect package won't give us an
// interface on certain things like unexported struct fields in order
- // to enforce visibility rules. We use unsafe to bypass these restrictions
- // since this package does not mutate the values.
+ // to enforce visibility rules. We use unsafe, when it's available,
+ // to bypass these restrictions since this package does not mutate the
+ // values.
if !v.CanInterface() {
+ if UnsafeDisabled {
+ return false
+ }
+
v = unsafeReflectValue(v)
}
@@ -206,21 +103,15 @@ func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool)
// mutate the value, however, types which choose to satisify an error or
// Stringer interface with a pointer receiver should not be mutating their
// state inside these interface methods.
- var viface interface{}
- if !cs.DisablePointerMethods {
- if !v.CanAddr() {
- v = unsafeReflectValue(v)
- }
- viface = v.Addr().Interface()
- } else {
- if v.CanAddr() {
- v = v.Addr()
- }
- viface = v.Interface()
+ if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() {
+ v = unsafeReflectValue(v)
+ }
+ if v.CanAddr() {
+ v = v.Addr()
}
// Is it an error or Stringer?
- switch iface := viface.(type) {
+ switch iface := v.Interface().(type) {
case error:
defer catchPanic(w, v)
if cs.ContinueOnMethod {
diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/common_test.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/common_test.go
deleted file mode 100644
index 39b7525b3..000000000
--- a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/common_test.go
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Copyright (c) 2013 Dave Collins <dave@davec.name>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-package spew_test
-
-import (
- "fmt"
- "reflect"
- "testing"
-
- "github.com/davecgh/go-spew/spew"
-)
-
-// custom type to test Stinger interface on non-pointer receiver.
-type stringer string
-
-// String implements the Stringer interface for testing invocation of custom
-// stringers on types with non-pointer receivers.
-func (s stringer) String() string {
- return "stringer " + string(s)
-}
-
-// custom type to test Stinger interface on pointer receiver.
-type pstringer string
-
-// String implements the Stringer interface for testing invocation of custom
-// stringers on types with only pointer receivers.
-func (s *pstringer) String() string {
- return "stringer " + string(*s)
-}
-
-// xref1 and xref2 are cross referencing structs for testing circular reference
-// detection.
-type xref1 struct {
- ps2 *xref2
-}
-type xref2 struct {
- ps1 *xref1
-}
-
-// indirCir1, indirCir2, and indirCir3 are used to generate an indirect circular
-// reference for testing detection.
-type indirCir1 struct {
- ps2 *indirCir2
-}
-type indirCir2 struct {
- ps3 *indirCir3
-}
-type indirCir3 struct {
- ps1 *indirCir1
-}
-
-// embed is used to test embedded structures.
-type embed struct {
- a string
-}
-
-// embedwrap is used to test embedded structures.
-type embedwrap struct {
- *embed
- e *embed
-}
-
-// panicer is used to intentionally cause a panic for testing spew properly
-// handles them
-type panicer int
-
-func (p panicer) String() string {
- panic("test panic")
-}
-
-// customError is used to test custom error interface invocation.
-type customError int
-
-func (e customError) Error() string {
- return fmt.Sprintf("error: %d", int(e))
-}
-
-// stringizeWants converts a slice of wanted test output into a format suitable
-// for a test error message.
-func stringizeWants(wants []string) string {
- s := ""
- for i, want := range wants {
- if i > 0 {
- s += fmt.Sprintf("want%d: %s", i+1, want)
- } else {
- s += "want: " + want
- }
- }
- return s
-}
-
-// testFailed returns whether or not a test failed by checking if the result
-// of the test is in the slice of wanted strings.
-func testFailed(result string, wants []string) bool {
- for _, want := range wants {
- if result == want {
- return false
- }
- }
- return true
-}
-
-type sortableStruct struct {
- x int
-}
-
-func (ss sortableStruct) String() string {
- return fmt.Sprintf("ss.%d", ss.x)
-}
-
-type unsortableStruct struct {
- x int
-}
-
-type sortTestCase struct {
- input []reflect.Value
- expected []reflect.Value
-}
-
-func helpTestSortValues(tests []sortTestCase, cs *spew.ConfigState, t *testing.T) {
- getInterfaces := func(values []reflect.Value) []interface{} {
- interfaces := []interface{}{}
- for _, v := range values {
- interfaces = append(interfaces, v.Interface())
- }
- return interfaces
- }
-
- for _, test := range tests {
- spew.SortValues(test.input, cs)
- // reflect.DeepEqual cannot really make sense of reflect.Value,
- // probably because of all the pointer tricks. For instance,
- // v(2.0) != v(2.0) on a 32-bits system. Turn them into interface{}
- // instead.
- input := getInterfaces(test.input)
- expected := getInterfaces(test.expected)
- if !reflect.DeepEqual(input, expected) {
- t.Errorf("Sort mismatch:\n %v != %v", input, expected)
- }
- }
-}
-
-// TestSortValues ensures the sort functionality for relect.Value based sorting
-// works as intended.
-func TestSortValues(t *testing.T) {
- v := reflect.ValueOf
-
- a := v("a")
- b := v("b")
- c := v("c")
- embedA := v(embed{"a"})
- embedB := v(embed{"b"})
- embedC := v(embed{"c"})
- tests := []sortTestCase{
- // No values.
- {
- []reflect.Value{},
- []reflect.Value{},
- },
- // Bools.
- {
- []reflect.Value{v(false), v(true), v(false)},
- []reflect.Value{v(false), v(false), v(true)},
- },
- // Ints.
- {
- []reflect.Value{v(2), v(1), v(3)},
- []reflect.Value{v(1), v(2), v(3)},
- },
- // Uints.
- {
- []reflect.Value{v(uint8(2)), v(uint8(1)), v(uint8(3))},
- []reflect.Value{v(uint8(1)), v(uint8(2)), v(uint8(3))},
- },
- // Floats.
- {
- []reflect.Value{v(2.0), v(1.0), v(3.0)},
- []reflect.Value{v(1.0), v(2.0), v(3.0)},
- },
- // Strings.
- {
- []reflect.Value{b, a, c},
- []reflect.Value{a, b, c},
- },
- // Array
- {
- []reflect.Value{v([3]int{3, 2, 1}), v([3]int{1, 3, 2}), v([3]int{1, 2, 3})},
- []reflect.Value{v([3]int{1, 2, 3}), v([3]int{1, 3, 2}), v([3]int{3, 2, 1})},
- },
- // Uintptrs.
- {
- []reflect.Value{v(uintptr(2)), v(uintptr(1)), v(uintptr(3))},
- []reflect.Value{v(uintptr(1)), v(uintptr(2)), v(uintptr(3))},
- },
- // SortableStructs.
- {
- // Note: not sorted - DisableMethods is set.
- []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
- []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
- },
- // UnsortableStructs.
- {
- // Note: not sorted - SpewKeys is false.
- []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
- []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
- },
- // Invalid.
- {
- []reflect.Value{embedB, embedA, embedC},
- []reflect.Value{embedB, embedA, embedC},
- },
- }
- cs := spew.ConfigState{DisableMethods: true, SpewKeys: false}
- helpTestSortValues(tests, &cs, t)
-}
-
-// TestSortValuesWithMethods ensures the sort functionality for relect.Value
-// based sorting works as intended when using string methods.
-func TestSortValuesWithMethods(t *testing.T) {
- v := reflect.ValueOf
-
- a := v("a")
- b := v("b")
- c := v("c")
- tests := []sortTestCase{
- // Ints.
- {
- []reflect.Value{v(2), v(1), v(3)},
- []reflect.Value{v(1), v(2), v(3)},
- },
- // Strings.
- {
- []reflect.Value{b, a, c},
- []reflect.Value{a, b, c},
- },
- // SortableStructs.
- {
- []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
- []reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})},
- },
- // UnsortableStructs.
- {
- // Note: not sorted - SpewKeys is false.
- []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
- []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
- },
- }
- cs := spew.ConfigState{DisableMethods: false, SpewKeys: false}
- helpTestSortValues(tests, &cs, t)
-}
-
-// TestSortValuesWithSpew ensures the sort functionality for relect.Value
-// based sorting works as intended when using spew to stringify keys.
-func TestSortValuesWithSpew(t *testing.T) {
- v := reflect.ValueOf
-
- a := v("a")
- b := v("b")
- c := v("c")
- tests := []sortTestCase{
- // Ints.
- {
- []reflect.Value{v(2), v(1), v(3)},
- []reflect.Value{v(1), v(2), v(3)},
- },
- // Strings.
- {
- []reflect.Value{b, a, c},
- []reflect.Value{a, b, c},
- },
- // SortableStructs.
- {
- []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
- []reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})},
- },
- // UnsortableStructs.
- {
- []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
- []reflect.Value{v(unsortableStruct{1}), v(unsortableStruct{2}), v(unsortableStruct{3})},
- },
- }
- cs := spew.ConfigState{DisableMethods: true, SpewKeys: true}
- helpTestSortValues(tests, &cs, t)
-}
diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/config.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/config.go
index 9e21b38ca..ee1ab07b3 100644
--- a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/config.go
+++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/config.go
@@ -61,7 +61,10 @@ type ConfigState struct {
// with a pointer receiver could technically mutate the value, however,
// in practice, types which choose to satisify an error or Stringer
// interface with a pointer receiver should not be mutating their state
- // inside these interface methods.
+ // inside these interface methods. As a result, this option relies on
+ // access to the unsafe package, so it will not have any effect when
+ // running in environments without access to the unsafe package such as
+ // Google App Engine or with the "disableunsafe" build tag specified.
DisablePointerMethods bool
// ContinueOnMethod specifies whether or not recursion should continue once
diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dump.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dump.go
index 5783145b7..a0ff95e27 100644
--- a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dump.go
+++ b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dump.go
@@ -181,25 +181,28 @@ func (d *dumpState) dumpSlice(v reflect.Value) {
// Try to use existing uint8 slices and fall back to converting
// and copying if that fails.
case vt.Kind() == reflect.Uint8:
- // We need an addressable interface to convert the type back
- // into a byte slice. However, the reflect package won't give
- // us an interface on certain things like unexported struct
- // fields in order to enforce visibility rules. We use unsafe
- // to bypass these restrictions since this package does not
+ // We need an addressable interface to convert the type
+ // to a byte slice. However, the reflect package won't
+ // give us an interface on certain things like
+ // unexported struct fields in order to enforce
+ // visibility rules. We use unsafe, when available, to
+ // bypass these restrictions since this package does not
// mutate the values.
vs := v
if !vs.CanInterface() || !vs.CanAddr() {
vs = unsafeReflectValue(vs)
}
- vs = vs.Slice(0, numEntries)
-
- // Use the existing uint8 slice if it can be type
- // asserted.
- iface := vs.Interface()
- if slice, ok := iface.([]uint8); ok {
- buf = slice
- doHexDump = true
- break
+ if !UnsafeDisabled {
+ vs = vs.Slice(0, numEntries)
+
+ // Use the existing uint8 slice if it can be
+ // type asserted.
+ iface := vs.Interface()
+ if slice, ok := iface.([]uint8); ok {
+ buf = slice
+ doHexDump = true
+ break
+ }
}
// The underlying data needs to be converted if it can't
diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dump_test.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dump_test.go
deleted file mode 100644
index 3dd908917..000000000
--- a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dump_test.go
+++ /dev/null
@@ -1,1021 +0,0 @@
-/*
- * Copyright (c) 2013 Dave Collins <dave@davec.name>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-/*
-Test Summary:
-NOTE: For each test, a nil pointer, a single pointer and double pointer to the
-base test element are also tested to ensure proper indirection across all types.
-
-- Max int8, int16, int32, int64, int
-- Max uint8, uint16, uint32, uint64, uint
-- Boolean true and false
-- Standard complex64 and complex128
-- Array containing standard ints
-- Array containing type with custom formatter on pointer receiver only
-- Array containing interfaces
-- Array containing bytes
-- Slice containing standard float32 values
-- Slice containing type with custom formatter on pointer receiver only
-- Slice containing interfaces
-- Slice containing bytes
-- Nil slice
-- Standard string
-- Nil interface
-- Sub-interface
-- Map with string keys and int vals
-- Map with custom formatter type on pointer receiver only keys and vals
-- Map with interface keys and values
-- Map with nil interface value
-- Struct with primitives
-- Struct that contains another struct
-- Struct that contains custom type with Stringer pointer interface via both
- exported and unexported fields
-- Struct that contains embedded struct and field to same struct
-- Uintptr to 0 (null pointer)
-- Uintptr address of real variable
-- Unsafe.Pointer to 0 (null pointer)
-- Unsafe.Pointer to address of real variable
-- Nil channel
-- Standard int channel
-- Function with no params and no returns
-- Function with param and no returns
-- Function with multiple params and multiple returns
-- Struct that is circular through self referencing
-- Structs that are circular through cross referencing
-- Structs that are indirectly circular
-- Type that panics in its Stringer interface
-*/
-
-package spew_test
-
-import (
- "bytes"
- "fmt"
- "testing"
- "unsafe"
-
- "github.com/davecgh/go-spew/spew"
-)
-
-// dumpTest is used to describe a test to be perfomed against the Dump method.
-type dumpTest struct {
- in interface{}
- wants []string
-}
-
-// dumpTests houses all of the tests to be performed against the Dump method.
-var dumpTests = make([]dumpTest, 0)
-
-// addDumpTest is a helper method to append the passed input and desired result
-// to dumpTests
-func addDumpTest(in interface{}, wants ...string) {
- test := dumpTest{in, wants}
- dumpTests = append(dumpTests, test)
-}
-
-func addIntDumpTests() {
- // Max int8.
- v := int8(127)
- nv := (*int8)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "int8"
- vs := "127"
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*"+vt+")(<nil>)\n")
-
- // Max int16.
- v2 := int16(32767)
- nv2 := (*int16)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "int16"
- v2s := "32767"
- addDumpTest(v2, "("+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
- addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
- addDumpTest(nv2, "(*"+v2t+")(<nil>)\n")
-
- // Max int32.
- v3 := int32(2147483647)
- nv3 := (*int32)(nil)
- pv3 := &v3
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "int32"
- v3s := "2147483647"
- addDumpTest(v3, "("+v3t+") "+v3s+"\n")
- addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
- addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
- addDumpTest(nv3, "(*"+v3t+")(<nil>)\n")
-
- // Max int64.
- v4 := int64(9223372036854775807)
- nv4 := (*int64)(nil)
- pv4 := &v4
- v4Addr := fmt.Sprintf("%p", pv4)
- pv4Addr := fmt.Sprintf("%p", &pv4)
- v4t := "int64"
- v4s := "9223372036854775807"
- addDumpTest(v4, "("+v4t+") "+v4s+"\n")
- addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
- addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
- addDumpTest(nv4, "(*"+v4t+")(<nil>)\n")
-
- // Max int.
- v5 := int(2147483647)
- nv5 := (*int)(nil)
- pv5 := &v5
- v5Addr := fmt.Sprintf("%p", pv5)
- pv5Addr := fmt.Sprintf("%p", &pv5)
- v5t := "int"
- v5s := "2147483647"
- addDumpTest(v5, "("+v5t+") "+v5s+"\n")
- addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n")
- addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n")
- addDumpTest(nv5, "(*"+v5t+")(<nil>)\n")
-}
-
-func addUintDumpTests() {
- // Max uint8.
- v := uint8(255)
- nv := (*uint8)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "uint8"
- vs := "255"
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*"+vt+")(<nil>)\n")
-
- // Max uint16.
- v2 := uint16(65535)
- nv2 := (*uint16)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "uint16"
- v2s := "65535"
- addDumpTest(v2, "("+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
- addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
- addDumpTest(nv2, "(*"+v2t+")(<nil>)\n")
-
- // Max uint32.
- v3 := uint32(4294967295)
- nv3 := (*uint32)(nil)
- pv3 := &v3
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "uint32"
- v3s := "4294967295"
- addDumpTest(v3, "("+v3t+") "+v3s+"\n")
- addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
- addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
- addDumpTest(nv3, "(*"+v3t+")(<nil>)\n")
-
- // Max uint64.
- v4 := uint64(18446744073709551615)
- nv4 := (*uint64)(nil)
- pv4 := &v4
- v4Addr := fmt.Sprintf("%p", pv4)
- pv4Addr := fmt.Sprintf("%p", &pv4)
- v4t := "uint64"
- v4s := "18446744073709551615"
- addDumpTest(v4, "("+v4t+") "+v4s+"\n")
- addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
- addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
- addDumpTest(nv4, "(*"+v4t+")(<nil>)\n")
-
- // Max uint.
- v5 := uint(4294967295)
- nv5 := (*uint)(nil)
- pv5 := &v5
- v5Addr := fmt.Sprintf("%p", pv5)
- pv5Addr := fmt.Sprintf("%p", &pv5)
- v5t := "uint"
- v5s := "4294967295"
- addDumpTest(v5, "("+v5t+") "+v5s+"\n")
- addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n")
- addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n")
- addDumpTest(nv5, "(*"+v5t+")(<nil>)\n")
-}
-
-func addBoolDumpTests() {
- // Boolean true.
- v := bool(true)
- nv := (*bool)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "bool"
- vs := "true"
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*"+vt+")(<nil>)\n")
-
- // Boolean false.
- v2 := bool(false)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "bool"
- v2s := "false"
- addDumpTest(v2, "("+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
- addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
-}
-
-func addFloatDumpTests() {
- // Standard float32.
- v := float32(3.1415)
- nv := (*float32)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "float32"
- vs := "3.1415"
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*"+vt+")(<nil>)\n")
-
- // Standard float64.
- v2 := float64(3.1415926)
- nv2 := (*float64)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "float64"
- v2s := "3.1415926"
- addDumpTest(v2, "("+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
- addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
- addDumpTest(nv2, "(*"+v2t+")(<nil>)\n")
-}
-
-func addComplexDumpTests() {
- // Standard complex64.
- v := complex(float32(6), -2)
- nv := (*complex64)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "complex64"
- vs := "(6-2i)"
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*"+vt+")(<nil>)\n")
-
- // Standard complex128.
- v2 := complex(float64(-6), 2)
- nv2 := (*complex128)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "complex128"
- v2s := "(-6+2i)"
- addDumpTest(v2, "("+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
- addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
- addDumpTest(nv2, "(*"+v2t+")(<nil>)\n")
-}
-
-func addArrayDumpTests() {
- // Array containing standard ints.
- v := [3]int{1, 2, 3}
- vLen := fmt.Sprintf("%d", len(v))
- vCap := fmt.Sprintf("%d", cap(v))
- nv := (*[3]int)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "int"
- vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 1,\n (" +
- vt + ") 2,\n (" + vt + ") 3\n}"
- addDumpTest(v, "([3]"+vt+") "+vs+"\n")
- addDumpTest(pv, "(*[3]"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**[3]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*[3]"+vt+")(<nil>)\n")
-
- // Array containing type with custom formatter on pointer receiver only.
- v2i0 := pstringer("1")
- v2i1 := pstringer("2")
- v2i2 := pstringer("3")
- v2 := [3]pstringer{v2i0, v2i1, v2i2}
- v2i0Len := fmt.Sprintf("%d", len(v2i0))
- v2i1Len := fmt.Sprintf("%d", len(v2i1))
- v2i2Len := fmt.Sprintf("%d", len(v2i2))
- v2Len := fmt.Sprintf("%d", len(v2))
- v2Cap := fmt.Sprintf("%d", cap(v2))
- nv2 := (*[3]pstringer)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "spew_test.pstringer"
- v2s := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + ") (len=" +
- v2i0Len + ") stringer 1,\n (" + v2t + ") (len=" + v2i1Len +
- ") stringer 2,\n (" + v2t + ") (len=" + v2i2Len + ") " +
- "stringer 3\n}"
- addDumpTest(v2, "([3]"+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*[3]"+v2t+")("+v2Addr+")("+v2s+")\n")
- addDumpTest(&pv2, "(**[3]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
- addDumpTest(nv2, "(*[3]"+v2t+")(<nil>)\n")
-
- // Array containing interfaces.
- v3i0 := "one"
- v3 := [3]interface{}{v3i0, int(2), uint(3)}
- v3i0Len := fmt.Sprintf("%d", len(v3i0))
- v3Len := fmt.Sprintf("%d", len(v3))
- v3Cap := fmt.Sprintf("%d", cap(v3))
- nv3 := (*[3]interface{})(nil)
- pv3 := &v3
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "[3]interface {}"
- v3t2 := "string"
- v3t3 := "int"
- v3t4 := "uint"
- v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " +
- "(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" +
- v3t4 + ") 3\n}"
- addDumpTest(v3, "("+v3t+") "+v3s+"\n")
- addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
- addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
- addDumpTest(nv3, "(*"+v3t+")(<nil>)\n")
-
- // Array containing bytes.
- v4 := [34]byte{
- 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
- 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
- 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
- 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
- 0x31, 0x32,
- }
- v4Len := fmt.Sprintf("%d", len(v4))
- v4Cap := fmt.Sprintf("%d", cap(v4))
- nv4 := (*[34]byte)(nil)
- pv4 := &v4
- v4Addr := fmt.Sprintf("%p", pv4)
- pv4Addr := fmt.Sprintf("%p", &pv4)
- v4t := "[34]uint8"
- v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " +
- "{\n 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20" +
- " |............... |\n" +
- " 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30" +
- " |!\"#$%&'()*+,-./0|\n" +
- " 00000020 31 32 " +
- " |12|\n}"
- addDumpTest(v4, "("+v4t+") "+v4s+"\n")
- addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
- addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
- addDumpTest(nv4, "(*"+v4t+")(<nil>)\n")
-}
-
-func addSliceDumpTests() {
- // Slice containing standard float32 values.
- v := []float32{3.14, 6.28, 12.56}
- vLen := fmt.Sprintf("%d", len(v))
- vCap := fmt.Sprintf("%d", cap(v))
- nv := (*[]float32)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "float32"
- vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 3.14,\n (" +
- vt + ") 6.28,\n (" + vt + ") 12.56\n}"
- addDumpTest(v, "([]"+vt+") "+vs+"\n")
- addDumpTest(pv, "(*[]"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**[]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*[]"+vt+")(<nil>)\n")
-
- // Slice containing type with custom formatter on pointer receiver only.
- v2i0 := pstringer("1")
- v2i1 := pstringer("2")
- v2i2 := pstringer("3")
- v2 := []pstringer{v2i0, v2i1, v2i2}
- v2i0Len := fmt.Sprintf("%d", len(v2i0))
- v2i1Len := fmt.Sprintf("%d", len(v2i1))
- v2i2Len := fmt.Sprintf("%d", len(v2i2))
- v2Len := fmt.Sprintf("%d", len(v2))
- v2Cap := fmt.Sprintf("%d", cap(v2))
- nv2 := (*[]pstringer)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "spew_test.pstringer"
- v2s := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + ") (len=" +
- v2i0Len + ") stringer 1,\n (" + v2t + ") (len=" + v2i1Len +
- ") stringer 2,\n (" + v2t + ") (len=" + v2i2Len + ") " +
- "stringer 3\n}"
- addDumpTest(v2, "([]"+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*[]"+v2t+")("+v2Addr+")("+v2s+")\n")
- addDumpTest(&pv2, "(**[]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
- addDumpTest(nv2, "(*[]"+v2t+")(<nil>)\n")
-
- // Slice containing interfaces.
- v3i0 := "one"
- v3 := []interface{}{v3i0, int(2), uint(3), nil}
- v3i0Len := fmt.Sprintf("%d", len(v3i0))
- v3Len := fmt.Sprintf("%d", len(v3))
- v3Cap := fmt.Sprintf("%d", cap(v3))
- nv3 := (*[]interface{})(nil)
- pv3 := &v3
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "[]interface {}"
- v3t2 := "string"
- v3t3 := "int"
- v3t4 := "uint"
- v3t5 := "interface {}"
- v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " +
- "(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" +
- v3t4 + ") 3,\n (" + v3t5 + ") <nil>\n}"
- addDumpTest(v3, "("+v3t+") "+v3s+"\n")
- addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
- addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
- addDumpTest(nv3, "(*"+v3t+")(<nil>)\n")
-
- // Slice containing bytes.
- v4 := []byte{
- 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
- 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
- 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
- 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
- 0x31, 0x32,
- }
- v4Len := fmt.Sprintf("%d", len(v4))
- v4Cap := fmt.Sprintf("%d", cap(v4))
- nv4 := (*[]byte)(nil)
- pv4 := &v4
- v4Addr := fmt.Sprintf("%p", pv4)
- pv4Addr := fmt.Sprintf("%p", &pv4)
- v4t := "[]uint8"
- v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " +
- "{\n 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20" +
- " |............... |\n" +
- " 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30" +
- " |!\"#$%&'()*+,-./0|\n" +
- " 00000020 31 32 " +
- " |12|\n}"
- addDumpTest(v4, "("+v4t+") "+v4s+"\n")
- addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
- addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
- addDumpTest(nv4, "(*"+v4t+")(<nil>)\n")
-
- // Nil slice.
- v5 := []int(nil)
- nv5 := (*[]int)(nil)
- pv5 := &v5
- v5Addr := fmt.Sprintf("%p", pv5)
- pv5Addr := fmt.Sprintf("%p", &pv5)
- v5t := "[]int"
- v5s := "<nil>"
- addDumpTest(v5, "("+v5t+") "+v5s+"\n")
- addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n")
- addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n")
- addDumpTest(nv5, "(*"+v5t+")(<nil>)\n")
-}
-
-func addStringDumpTests() {
- // Standard string.
- v := "test"
- vLen := fmt.Sprintf("%d", len(v))
- nv := (*string)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "string"
- vs := "(len=" + vLen + ") \"test\""
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*"+vt+")(<nil>)\n")
-}
-
-func addInterfaceDumpTests() {
- // Nil interface.
- var v interface{}
- nv := (*interface{})(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "interface {}"
- vs := "<nil>"
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*"+vt+")(<nil>)\n")
-
- // Sub-interface.
- v2 := interface{}(uint16(65535))
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "uint16"
- v2s := "65535"
- addDumpTest(v2, "("+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
- addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
-}
-
-func addMapDumpTests() {
- // Map with string keys and int vals.
- k := "one"
- kk := "two"
- m := map[string]int{k: 1, kk: 2}
- klen := fmt.Sprintf("%d", len(k)) // not kLen to shut golint up
- kkLen := fmt.Sprintf("%d", len(kk))
- mLen := fmt.Sprintf("%d", len(m))
- nilMap := map[string]int(nil)
- nm := (*map[string]int)(nil)
- pm := &m
- mAddr := fmt.Sprintf("%p", pm)
- pmAddr := fmt.Sprintf("%p", &pm)
- mt := "map[string]int"
- mt1 := "string"
- mt2 := "int"
- ms := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + klen + ") " +
- "\"one\": (" + mt2 + ") 1,\n (" + mt1 + ") (len=" + kkLen +
- ") \"two\": (" + mt2 + ") 2\n}"
- ms2 := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + kkLen + ") " +
- "\"two\": (" + mt2 + ") 2,\n (" + mt1 + ") (len=" + klen +
- ") \"one\": (" + mt2 + ") 1\n}"
- addDumpTest(m, "("+mt+") "+ms+"\n", "("+mt+") "+ms2+"\n")
- addDumpTest(pm, "(*"+mt+")("+mAddr+")("+ms+")\n",
- "(*"+mt+")("+mAddr+")("+ms2+")\n")
- addDumpTest(&pm, "(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms+")\n",
- "(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms2+")\n")
- addDumpTest(nm, "(*"+mt+")(<nil>)\n")
- addDumpTest(nilMap, "("+mt+") <nil>\n")
-
- // Map with custom formatter type on pointer receiver only keys and vals.
- k2 := pstringer("one")
- v2 := pstringer("1")
- m2 := map[pstringer]pstringer{k2: v2}
- k2Len := fmt.Sprintf("%d", len(k2))
- v2Len := fmt.Sprintf("%d", len(v2))
- m2Len := fmt.Sprintf("%d", len(m2))
- nilMap2 := map[pstringer]pstringer(nil)
- nm2 := (*map[pstringer]pstringer)(nil)
- pm2 := &m2
- m2Addr := fmt.Sprintf("%p", pm2)
- pm2Addr := fmt.Sprintf("%p", &pm2)
- m2t := "map[spew_test.pstringer]spew_test.pstringer"
- m2t1 := "spew_test.pstringer"
- m2t2 := "spew_test.pstringer"
- m2s := "(len=" + m2Len + ") {\n (" + m2t1 + ") (len=" + k2Len + ") " +
- "stringer one: (" + m2t2 + ") (len=" + v2Len + ") stringer 1\n}"
- addDumpTest(m2, "("+m2t+") "+m2s+"\n")
- addDumpTest(pm2, "(*"+m2t+")("+m2Addr+")("+m2s+")\n")
- addDumpTest(&pm2, "(**"+m2t+")("+pm2Addr+"->"+m2Addr+")("+m2s+")\n")
- addDumpTest(nm2, "(*"+m2t+")(<nil>)\n")
- addDumpTest(nilMap2, "("+m2t+") <nil>\n")
-
- // Map with interface keys and values.
- k3 := "one"
- k3Len := fmt.Sprintf("%d", len(k3))
- m3 := map[interface{}]interface{}{k3: 1}
- m3Len := fmt.Sprintf("%d", len(m3))
- nilMap3 := map[interface{}]interface{}(nil)
- nm3 := (*map[interface{}]interface{})(nil)
- pm3 := &m3
- m3Addr := fmt.Sprintf("%p", pm3)
- pm3Addr := fmt.Sprintf("%p", &pm3)
- m3t := "map[interface {}]interface {}"
- m3t1 := "string"
- m3t2 := "int"
- m3s := "(len=" + m3Len + ") {\n (" + m3t1 + ") (len=" + k3Len + ") " +
- "\"one\": (" + m3t2 + ") 1\n}"
- addDumpTest(m3, "("+m3t+") "+m3s+"\n")
- addDumpTest(pm3, "(*"+m3t+")("+m3Addr+")("+m3s+")\n")
- addDumpTest(&pm3, "(**"+m3t+")("+pm3Addr+"->"+m3Addr+")("+m3s+")\n")
- addDumpTest(nm3, "(*"+m3t+")(<nil>)\n")
- addDumpTest(nilMap3, "("+m3t+") <nil>\n")
-
- // Map with nil interface value.
- k4 := "nil"
- k4Len := fmt.Sprintf("%d", len(k4))
- m4 := map[string]interface{}{k4: nil}
- m4Len := fmt.Sprintf("%d", len(m4))
- nilMap4 := map[string]interface{}(nil)
- nm4 := (*map[string]interface{})(nil)
- pm4 := &m4
- m4Addr := fmt.Sprintf("%p", pm4)
- pm4Addr := fmt.Sprintf("%p", &pm4)
- m4t := "map[string]interface {}"
- m4t1 := "string"
- m4t2 := "interface {}"
- m4s := "(len=" + m4Len + ") {\n (" + m4t1 + ") (len=" + k4Len + ")" +
- " \"nil\": (" + m4t2 + ") <nil>\n}"
- addDumpTest(m4, "("+m4t+") "+m4s+"\n")
- addDumpTest(pm4, "(*"+m4t+")("+m4Addr+")("+m4s+")\n")
- addDumpTest(&pm4, "(**"+m4t+")("+pm4Addr+"->"+m4Addr+")("+m4s+")\n")
- addDumpTest(nm4, "(*"+m4t+")(<nil>)\n")
- addDumpTest(nilMap4, "("+m4t+") <nil>\n")
-}
-
-func addStructDumpTests() {
- // Struct with primitives.
- type s1 struct {
- a int8
- b uint8
- }
- v := s1{127, 255}
- nv := (*s1)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "spew_test.s1"
- vt2 := "int8"
- vt3 := "uint8"
- vs := "{\n a: (" + vt2 + ") 127,\n b: (" + vt3 + ") 255\n}"
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*"+vt+")(<nil>)\n")
-
- // Struct that contains another struct.
- type s2 struct {
- s1 s1
- b bool
- }
- v2 := s2{s1{127, 255}, true}
- nv2 := (*s2)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "spew_test.s2"
- v2t2 := "spew_test.s1"
- v2t3 := "int8"
- v2t4 := "uint8"
- v2t5 := "bool"
- v2s := "{\n s1: (" + v2t2 + ") {\n a: (" + v2t3 + ") 127,\n b: (" +
- v2t4 + ") 255\n },\n b: (" + v2t5 + ") true\n}"
- addDumpTest(v2, "("+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
- addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
- addDumpTest(nv2, "(*"+v2t+")(<nil>)\n")
-
- // Struct that contains custom type with Stringer pointer interface via both
- // exported and unexported fields.
- type s3 struct {
- s pstringer
- S pstringer
- }
- v3 := s3{"test", "test2"}
- nv3 := (*s3)(nil)
- pv3 := &v3
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "spew_test.s3"
- v3t2 := "spew_test.pstringer"
- v3s := "{\n s: (" + v3t2 + ") (len=4) stringer test,\n S: (" + v3t2 +
- ") (len=5) stringer test2\n}"
- addDumpTest(v3, "("+v3t+") "+v3s+"\n")
- addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
- addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
- addDumpTest(nv3, "(*"+v3t+")(<nil>)\n")
-
- // Struct that contains embedded struct and field to same struct.
- e := embed{"embedstr"}
- eLen := fmt.Sprintf("%d", len("embedstr"))
- v4 := embedwrap{embed: &e, e: &e}
- nv4 := (*embedwrap)(nil)
- pv4 := &v4
- eAddr := fmt.Sprintf("%p", &e)
- v4Addr := fmt.Sprintf("%p", pv4)
- pv4Addr := fmt.Sprintf("%p", &pv4)
- v4t := "spew_test.embedwrap"
- v4t2 := "spew_test.embed"
- v4t3 := "string"
- v4s := "{\n embed: (*" + v4t2 + ")(" + eAddr + ")({\n a: (" + v4t3 +
- ") (len=" + eLen + ") \"embedstr\"\n }),\n e: (*" + v4t2 +
- ")(" + eAddr + ")({\n a: (" + v4t3 + ") (len=" + eLen + ")" +
- " \"embedstr\"\n })\n}"
- addDumpTest(v4, "("+v4t+") "+v4s+"\n")
- addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
- addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
- addDumpTest(nv4, "(*"+v4t+")(<nil>)\n")
-}
-
-func addUintptrDumpTests() {
- // Null pointer.
- v := uintptr(0)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "uintptr"
- vs := "<nil>"
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
-
- // Address of real variable.
- i := 1
- v2 := uintptr(unsafe.Pointer(&i))
- nv2 := (*uintptr)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "uintptr"
- v2s := fmt.Sprintf("%p", &i)
- addDumpTest(v2, "("+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
- addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
- addDumpTest(nv2, "(*"+v2t+")(<nil>)\n")
-}
-
-func addUnsafePointerDumpTests() {
- // Null pointer.
- v := unsafe.Pointer(uintptr(0))
- nv := (*unsafe.Pointer)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "unsafe.Pointer"
- vs := "<nil>"
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*"+vt+")(<nil>)\n")
-
- // Address of real variable.
- i := 1
- v2 := unsafe.Pointer(&i)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "unsafe.Pointer"
- v2s := fmt.Sprintf("%p", &i)
- addDumpTest(v2, "("+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
- addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
- addDumpTest(nv, "(*"+vt+")(<nil>)\n")
-}
-
-func addChanDumpTests() {
- // Nil channel.
- var v chan int
- pv := &v
- nv := (*chan int)(nil)
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "chan int"
- vs := "<nil>"
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*"+vt+")(<nil>)\n")
-
- // Real channel.
- v2 := make(chan int)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "chan int"
- v2s := fmt.Sprintf("%p", v2)
- addDumpTest(v2, "("+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
- addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
-}
-
-func addFuncDumpTests() {
- // Function with no params and no returns.
- v := addIntDumpTests
- nv := (*func())(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "func()"
- vs := fmt.Sprintf("%p", v)
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*"+vt+")(<nil>)\n")
-
- // Function with param and no returns.
- v2 := TestDump
- nv2 := (*func(*testing.T))(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "func(*testing.T)"
- v2s := fmt.Sprintf("%p", v2)
- addDumpTest(v2, "("+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
- addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
- addDumpTest(nv2, "(*"+v2t+")(<nil>)\n")
-
- // Function with multiple params and multiple returns.
- var v3 = func(i int, s string) (b bool, err error) {
- return true, nil
- }
- nv3 := (*func(int, string) (bool, error))(nil)
- pv3 := &v3
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "func(int, string) (bool, error)"
- v3s := fmt.Sprintf("%p", v3)
- addDumpTest(v3, "("+v3t+") "+v3s+"\n")
- addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
- addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
- addDumpTest(nv3, "(*"+v3t+")(<nil>)\n")
-}
-
-func addCircularDumpTests() {
- // Struct that is circular through self referencing.
- type circular struct {
- c *circular
- }
- v := circular{nil}
- v.c = &v
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "spew_test.circular"
- vs := "{\n c: (*" + vt + ")(" + vAddr + ")({\n c: (*" + vt + ")(" +
- vAddr + ")(<already shown>)\n })\n}"
- vs2 := "{\n c: (*" + vt + ")(" + vAddr + ")(<already shown>)\n}"
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs2+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs2+")\n")
-
- // Structs that are circular through cross referencing.
- v2 := xref1{nil}
- ts2 := xref2{&v2}
- v2.ps2 = &ts2
- pv2 := &v2
- ts2Addr := fmt.Sprintf("%p", &ts2)
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "spew_test.xref1"
- v2t2 := "spew_test.xref2"
- v2s := "{\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")({\n ps1: (*" + v2t +
- ")(" + v2Addr + ")({\n ps2: (*" + v2t2 + ")(" + ts2Addr +
- ")(<already shown>)\n })\n })\n}"
- v2s2 := "{\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")({\n ps1: (*" + v2t +
- ")(" + v2Addr + ")(<already shown>)\n })\n}"
- addDumpTest(v2, "("+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s2+")\n")
- addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s2+")\n")
-
- // Structs that are indirectly circular.
- v3 := indirCir1{nil}
- tic2 := indirCir2{nil}
- tic3 := indirCir3{&v3}
- tic2.ps3 = &tic3
- v3.ps2 = &tic2
- pv3 := &v3
- tic2Addr := fmt.Sprintf("%p", &tic2)
- tic3Addr := fmt.Sprintf("%p", &tic3)
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "spew_test.indirCir1"
- v3t2 := "spew_test.indirCir2"
- v3t3 := "spew_test.indirCir3"
- v3s := "{\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")({\n ps3: (*" + v3t3 +
- ")(" + tic3Addr + ")({\n ps1: (*" + v3t + ")(" + v3Addr +
- ")({\n ps2: (*" + v3t2 + ")(" + tic2Addr +
- ")(<already shown>)\n })\n })\n })\n}"
- v3s2 := "{\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")({\n ps3: (*" + v3t3 +
- ")(" + tic3Addr + ")({\n ps1: (*" + v3t + ")(" + v3Addr +
- ")(<already shown>)\n })\n })\n}"
- addDumpTest(v3, "("+v3t+") "+v3s+"\n")
- addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s2+")\n")
- addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s2+")\n")
-}
-
-func addPanicDumpTests() {
- // Type that panics in its Stringer interface.
- v := panicer(127)
- nv := (*panicer)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "spew_test.panicer"
- vs := "(PANIC=test panic)127"
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*"+vt+")(<nil>)\n")
-}
-
-func addErrorDumpTests() {
- // Type that has a custom Error interface.
- v := customError(127)
- nv := (*customError)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "spew_test.customError"
- vs := "error: 127"
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*"+vt+")(<nil>)\n")
-}
-
-// TestDump executes all of the tests described by dumpTests.
-func TestDump(t *testing.T) {
- // Setup tests.
- addIntDumpTests()
- addUintDumpTests()
- addBoolDumpTests()
- addFloatDumpTests()
- addComplexDumpTests()
- addArrayDumpTests()
- addSliceDumpTests()
- addStringDumpTests()
- addInterfaceDumpTests()
- addMapDumpTests()
- addStructDumpTests()
- addUintptrDumpTests()
- addUnsafePointerDumpTests()
- addChanDumpTests()
- addFuncDumpTests()
- addCircularDumpTests()
- addPanicDumpTests()
- addErrorDumpTests()
- addCgoDumpTests()
-
- t.Logf("Running %d tests", len(dumpTests))
- for i, test := range dumpTests {
- buf := new(bytes.Buffer)
- spew.Fdump(buf, test.in)
- s := buf.String()
- if testFailed(s, test.wants) {
- t.Errorf("Dump #%d\n got: %s %s", i, s, stringizeWants(test.wants))
- continue
- }
- }
-}
-
-func TestDumpSortedKeys(t *testing.T) {
- cfg := spew.ConfigState{SortKeys: true}
- s := cfg.Sdump(map[int]string{1: "1", 3: "3", 2: "2"})
- expected := `(map[int]string) (len=3) {
-(int) 1: (string) (len=1) "1",
-(int) 2: (string) (len=1) "2",
-(int) 3: (string) (len=1) "3"
-}
-`
- if s != expected {
- t.Errorf("Sorted keys mismatch:\n %v %v", s, expected)
- }
-
- s = cfg.Sdump(map[stringer]int{"1": 1, "3": 3, "2": 2})
- expected = `(map[spew_test.stringer]int) (len=3) {
-(spew_test.stringer) (len=1) stringer 1: (int) 1,
-(spew_test.stringer) (len=1) stringer 2: (int) 2,
-(spew_test.stringer) (len=1) stringer 3: (int) 3
-}
-`
- if s != expected {
- t.Errorf("Sorted keys mismatch:\n %v %v", s, expected)
- }
-
- s = cfg.Sdump(map[pstringer]int{pstringer("1"): 1, pstringer("3"): 3, pstringer("2"): 2})
- expected = `(map[spew_test.pstringer]int) (len=3) {
-(spew_test.pstringer) (len=1) stringer 1: (int) 1,
-(spew_test.pstringer) (len=1) stringer 2: (int) 2,
-(spew_test.pstringer) (len=1) stringer 3: (int) 3
-}
-`
- if s != expected {
- t.Errorf("Sorted keys mismatch:\n %v %v", s, expected)
- }
-
- s = cfg.Sdump(map[customError]int{customError(1): 1, customError(3): 3, customError(2): 2})
- expected = `(map[spew_test.customError]int) (len=3) {
-(spew_test.customError) error: 1: (int) 1,
-(spew_test.customError) error: 2: (int) 2,
-(spew_test.customError) error: 3: (int) 3
-}
-`
- if s != expected {
- t.Errorf("Sorted keys mismatch:\n %v %v", s, expected)
- }
-
-}
diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dumpcgo_test.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dumpcgo_test.go
deleted file mode 100644
index 9b8a358ec..000000000
--- a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dumpcgo_test.go
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright (c) 2013 Dave Collins <dave@davec.name>
-//
-// Permission to use, copy, modify, and distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-// NOTE: Due to the following build constraints, this file will only be compiled
-// when both cgo is supported and "-tags testcgo" is added to the go test
-// command line. This means the cgo tests are only added (and hence run) when
-// specifially requested. This configuration is used because spew itself
-// does not require cgo to run even though it does handle certain cgo types
-// specially. Rather than forcing all clients to require cgo and an external
-// C compiler just to run the tests, this scheme makes them optional.
-// +build cgo,testcgo
-
-package spew_test
-
-import (
- "fmt"
- "github.com/davecgh/go-spew/spew/testdata"
-)
-
-func addCgoDumpTests() {
- // C char pointer.
- v := testdata.GetCgoCharPointer()
- nv := testdata.GetCgoNullCharPointer()
- pv := &v
- vcAddr := fmt.Sprintf("%p", v)
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "*testdata._Ctype_char"
- vs := "116"
- addDumpTest(v, "("+vt+")("+vcAddr+")("+vs+")\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+"->"+vcAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+"->"+vcAddr+")("+vs+")\n")
- addDumpTest(nv, "("+vt+")(<nil>)\n")
-
- // C char array.
- v2, v2l, v2c := testdata.GetCgoCharArray()
- v2Len := fmt.Sprintf("%d", v2l)
- v2Cap := fmt.Sprintf("%d", v2c)
- v2t := "[6]testdata._Ctype_char"
- v2s := "(len=" + v2Len + " cap=" + v2Cap + ") " +
- "{\n 00000000 74 65 73 74 32 00 " +
- " |test2.|\n}"
- addDumpTest(v2, "("+v2t+") "+v2s+"\n")
-
- // C unsigned char array.
- v3, v3l, v3c := testdata.GetCgoUnsignedCharArray()
- v3Len := fmt.Sprintf("%d", v3l)
- v3Cap := fmt.Sprintf("%d", v3c)
- v3t := "[6]testdata._Ctype_unsignedchar"
- v3s := "(len=" + v3Len + " cap=" + v3Cap + ") " +
- "{\n 00000000 74 65 73 74 33 00 " +
- " |test3.|\n}"
- addDumpTest(v3, "("+v3t+") "+v3s+"\n")
-
- // C signed char array.
- v4, v4l, v4c := testdata.GetCgoSignedCharArray()
- v4Len := fmt.Sprintf("%d", v4l)
- v4Cap := fmt.Sprintf("%d", v4c)
- v4t := "[6]testdata._Ctype_schar"
- v4t2 := "testdata._Ctype_schar"
- v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " +
- "{\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 101,\n (" + v4t2 +
- ") 115,\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 52,\n (" + v4t2 +
- ") 0\n}"
- addDumpTest(v4, "("+v4t+") "+v4s+"\n")
-
- // C uint8_t array.
- v5, v5l, v5c := testdata.GetCgoUint8tArray()
- v5Len := fmt.Sprintf("%d", v5l)
- v5Cap := fmt.Sprintf("%d", v5c)
- v5t := "[6]testdata._Ctype_uint8_t"
- v5s := "(len=" + v5Len + " cap=" + v5Cap + ") " +
- "{\n 00000000 74 65 73 74 35 00 " +
- " |test5.|\n}"
- addDumpTest(v5, "("+v5t+") "+v5s+"\n")
-
- // C typedefed unsigned char array.
- v6, v6l, v6c := testdata.GetCgoTypdefedUnsignedCharArray()
- v6Len := fmt.Sprintf("%d", v6l)
- v6Cap := fmt.Sprintf("%d", v6c)
- v6t := "[6]testdata._Ctype_custom_uchar_t"
- v6s := "(len=" + v6Len + " cap=" + v6Cap + ") " +
- "{\n 00000000 74 65 73 74 36 00 " +
- " |test6.|\n}"
- addDumpTest(v6, "("+v6t+") "+v6s+"\n")
-}
diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dumpnocgo_test.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dumpnocgo_test.go
deleted file mode 100644
index 52a0971fb..000000000
--- a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/dumpnocgo_test.go
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2013 Dave Collins <dave@davec.name>
-//
-// Permission to use, copy, modify, and distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-// NOTE: Due to the following build constraints, this file will only be compiled
-// when either cgo is not supported or "-tags testcgo" is not added to the go
-// test command line. This file intentionally does not setup any cgo tests in
-// this scenario.
-// +build !cgo !testcgo
-
-package spew_test
-
-func addCgoDumpTests() {
- // Don't add any tests for cgo since this file is only compiled when
- // there should not be any cgo tests.
-}
diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/example_test.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/example_test.go
deleted file mode 100644
index a7acd1412..000000000
--- a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/example_test.go
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (c) 2013 Dave Collins <dave@davec.name>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-package spew_test
-
-import (
- "fmt"
- "github.com/davecgh/go-spew/spew"
-)
-
-type Flag int
-
-const (
- flagOne Flag = iota
- flagTwo
-)
-
-var flagStrings = map[Flag]string{
- flagOne: "flagOne",
- flagTwo: "flagTwo",
-}
-
-func (f Flag) String() string {
- if s, ok := flagStrings[f]; ok {
- return s
- }
- return fmt.Sprintf("Unknown flag (%d)", int(f))
-}
-
-type Bar struct {
- flag Flag
- data uintptr
-}
-
-type Foo struct {
- unexportedField Bar
- ExportedField map[interface{}]interface{}
-}
-
-// This example demonstrates how to use Dump to dump variables to stdout.
-func ExampleDump() {
- // The following package level declarations are assumed for this example:
- /*
- type Flag int
-
- const (
- flagOne Flag = iota
- flagTwo
- )
-
- var flagStrings = map[Flag]string{
- flagOne: "flagOne",
- flagTwo: "flagTwo",
- }
-
- func (f Flag) String() string {
- if s, ok := flagStrings[f]; ok {
- return s
- }
- return fmt.Sprintf("Unknown flag (%d)", int(f))
- }
-
- type Bar struct {
- flag Flag
- data uintptr
- }
-
- type Foo struct {
- unexportedField Bar
- ExportedField map[interface{}]interface{}
- }
- */
-
- // Setup some sample data structures for the example.
- bar := Bar{Flag(flagTwo), uintptr(0)}
- s1 := Foo{bar, map[interface{}]interface{}{"one": true}}
- f := Flag(5)
- b := []byte{
- 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
- 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
- 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
- 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
- 0x31, 0x32,
- }
-
- // Dump!
- spew.Dump(s1, f, b)
-
- // Output:
- // (spew_test.Foo) {
- // unexportedField: (spew_test.Bar) {
- // flag: (spew_test.Flag) flagTwo,
- // data: (uintptr) <nil>
- // },
- // ExportedField: (map[interface {}]interface {}) (len=1) {
- // (string) (len=3) "one": (bool) true
- // }
- // }
- // (spew_test.Flag) Unknown flag (5)
- // ([]uint8) (len=34 cap=34) {
- // 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... |
- // 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0|
- // 00000020 31 32 |12|
- // }
- //
-}
-
-// This example demonstrates how to use Printf to display a variable with a
-// format string and inline formatting.
-func ExamplePrintf() {
- // Create a double pointer to a uint 8.
- ui8 := uint8(5)
- pui8 := &ui8
- ppui8 := &pui8
-
- // Create a circular data type.
- type circular struct {
- ui8 uint8
- c *circular
- }
- c := circular{ui8: 1}
- c.c = &c
-
- // Print!
- spew.Printf("ppui8: %v\n", ppui8)
- spew.Printf("circular: %v\n", c)
-
- // Output:
- // ppui8: <**>5
- // circular: {1 <*>{1 <*><shown>}}
-}
-
-// This example demonstrates how to use a ConfigState.
-func ExampleConfigState() {
- // Modify the indent level of the ConfigState only. The global
- // configuration is not modified.
- scs := spew.ConfigState{Indent: "\t"}
-
- // Output using the ConfigState instance.
- v := map[string]int{"one": 1}
- scs.Printf("v: %v\n", v)
- scs.Dump(v)
-
- // Output:
- // v: map[one:1]
- // (map[string]int) (len=1) {
- // (string) (len=3) "one": (int) 1
- // }
-}
-
-// This example demonstrates how to use ConfigState.Dump to dump variables to
-// stdout
-func ExampleConfigState_Dump() {
- // See the top-level Dump example for details on the types used in this
- // example.
-
- // Create two ConfigState instances with different indentation.
- scs := spew.ConfigState{Indent: "\t"}
- scs2 := spew.ConfigState{Indent: " "}
-
- // Setup some sample data structures for the example.
- bar := Bar{Flag(flagTwo), uintptr(0)}
- s1 := Foo{bar, map[interface{}]interface{}{"one": true}}
-
- // Dump using the ConfigState instances.
- scs.Dump(s1)
- scs2.Dump(s1)
-
- // Output:
- // (spew_test.Foo) {
- // unexportedField: (spew_test.Bar) {
- // flag: (spew_test.Flag) flagTwo,
- // data: (uintptr) <nil>
- // },
- // ExportedField: (map[interface {}]interface {}) (len=1) {
- // (string) (len=3) "one": (bool) true
- // }
- // }
- // (spew_test.Foo) {
- // unexportedField: (spew_test.Bar) {
- // flag: (spew_test.Flag) flagTwo,
- // data: (uintptr) <nil>
- // },
- // ExportedField: (map[interface {}]interface {}) (len=1) {
- // (string) (len=3) "one": (bool) true
- // }
- // }
- //
-}
-
-// This example demonstrates how to use ConfigState.Printf to display a variable
-// with a format string and inline formatting.
-func ExampleConfigState_Printf() {
- // See the top-level Dump example for details on the types used in this
- // example.
-
- // Create two ConfigState instances and modify the method handling of the
- // first ConfigState only.
- scs := spew.NewDefaultConfig()
- scs2 := spew.NewDefaultConfig()
- scs.DisableMethods = true
-
- // Alternatively
- // scs := spew.ConfigState{Indent: " ", DisableMethods: true}
- // scs2 := spew.ConfigState{Indent: " "}
-
- // This is of type Flag which implements a Stringer and has raw value 1.
- f := flagTwo
-
- // Dump using the ConfigState instances.
- scs.Printf("f: %v\n", f)
- scs2.Printf("f: %v\n", f)
-
- // Output:
- // f: 1
- // f: flagTwo
-}
diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/format_test.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/format_test.go
deleted file mode 100644
index b0f9761a4..000000000
--- a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/format_test.go
+++ /dev/null
@@ -1,1535 +0,0 @@
-/*
- * Copyright (c) 2013 Dave Collins <dave@davec.name>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-/*
-Test Summary:
-NOTE: For each test, a nil pointer, a single pointer and double pointer to the
-base test element are also tested to ensure proper indirection across all types.
-
-- Max int8, int16, int32, int64, int
-- Max uint8, uint16, uint32, uint64, uint
-- Boolean true and false
-- Standard complex64 and complex128
-- Array containing standard ints
-- Array containing type with custom formatter on pointer receiver only
-- Array containing interfaces
-- Slice containing standard float32 values
-- Slice containing type with custom formatter on pointer receiver only
-- Slice containing interfaces
-- Nil slice
-- Standard string
-- Nil interface
-- Sub-interface
-- Map with string keys and int vals
-- Map with custom formatter type on pointer receiver only keys and vals
-- Map with interface keys and values
-- Map with nil interface value
-- Struct with primitives
-- Struct that contains another struct
-- Struct that contains custom type with Stringer pointer interface via both
- exported and unexported fields
-- Struct that contains embedded struct and field to same struct
-- Uintptr to 0 (null pointer)
-- Uintptr address of real variable
-- Unsafe.Pointer to 0 (null pointer)
-- Unsafe.Pointer to address of real variable
-- Nil channel
-- Standard int channel
-- Function with no params and no returns
-- Function with param and no returns
-- Function with multiple params and multiple returns
-- Struct that is circular through self referencing
-- Structs that are circular through cross referencing
-- Structs that are indirectly circular
-- Type that panics in its Stringer interface
-- Type that has a custom Error interface
-- %x passthrough with uint
-- %#x passthrough with uint
-- %f passthrough with precision
-- %f passthrough with width and precision
-- %d passthrough with width
-- %q passthrough with string
-*/
-
-package spew_test
-
-import (
- "bytes"
- "fmt"
- "testing"
- "unsafe"
-
- "github.com/davecgh/go-spew/spew"
-)
-
-// formatterTest is used to describe a test to be perfomed against NewFormatter.
-type formatterTest struct {
- format string
- in interface{}
- wants []string
-}
-
-// formatterTests houses all of the tests to be performed against NewFormatter.
-var formatterTests = make([]formatterTest, 0)
-
-// addFormatterTest is a helper method to append the passed input and desired
-// result to formatterTests.
-func addFormatterTest(format string, in interface{}, wants ...string) {
- test := formatterTest{format, in, wants}
- formatterTests = append(formatterTests, test)
-}
-
-func addIntFormatterTests() {
- // Max int8.
- v := int8(127)
- nv := (*int8)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "int8"
- vs := "127"
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%v", nv, "<nil>")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
-
- // Max int16.
- v2 := int16(32767)
- nv2 := (*int16)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "int16"
- v2s := "32767"
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s)
- addFormatterTest("%v", &pv2, "<**>"+v2s)
- addFormatterTest("%v", nv2, "<nil>")
- addFormatterTest("%+v", v2, v2s)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%+v", nv2, "<nil>")
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
- addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
-
- // Max int32.
- v3 := int32(2147483647)
- nv3 := (*int32)(nil)
- pv3 := &v3
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "int32"
- v3s := "2147483647"
- addFormatterTest("%v", v3, v3s)
- addFormatterTest("%v", pv3, "<*>"+v3s)
- addFormatterTest("%v", &pv3, "<**>"+v3s)
- addFormatterTest("%v", nv3, "<nil>")
- addFormatterTest("%+v", v3, v3s)
- addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
- addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
- addFormatterTest("%+v", nv3, "<nil>")
- addFormatterTest("%#v", v3, "("+v3t+")"+v3s)
- addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s)
- addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s)
- addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
- addFormatterTest("%#+v", v3, "("+v3t+")"+v3s)
- addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s)
- addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s)
- addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
-
- // Max int64.
- v4 := int64(9223372036854775807)
- nv4 := (*int64)(nil)
- pv4 := &v4
- v4Addr := fmt.Sprintf("%p", pv4)
- pv4Addr := fmt.Sprintf("%p", &pv4)
- v4t := "int64"
- v4s := "9223372036854775807"
- addFormatterTest("%v", v4, v4s)
- addFormatterTest("%v", pv4, "<*>"+v4s)
- addFormatterTest("%v", &pv4, "<**>"+v4s)
- addFormatterTest("%v", nv4, "<nil>")
- addFormatterTest("%+v", v4, v4s)
- addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
- addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
- addFormatterTest("%+v", nv4, "<nil>")
- addFormatterTest("%#v", v4, "("+v4t+")"+v4s)
- addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s)
- addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s)
- addFormatterTest("%#v", nv4, "(*"+v4t+")"+"<nil>")
- addFormatterTest("%#+v", v4, "("+v4t+")"+v4s)
- addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s)
- addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s)
- addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"<nil>")
-
- // Max int.
- v5 := int(2147483647)
- nv5 := (*int)(nil)
- pv5 := &v5
- v5Addr := fmt.Sprintf("%p", pv5)
- pv5Addr := fmt.Sprintf("%p", &pv5)
- v5t := "int"
- v5s := "2147483647"
- addFormatterTest("%v", v5, v5s)
- addFormatterTest("%v", pv5, "<*>"+v5s)
- addFormatterTest("%v", &pv5, "<**>"+v5s)
- addFormatterTest("%v", nv5, "<nil>")
- addFormatterTest("%+v", v5, v5s)
- addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s)
- addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s)
- addFormatterTest("%+v", nv5, "<nil>")
- addFormatterTest("%#v", v5, "("+v5t+")"+v5s)
- addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s)
- addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s)
- addFormatterTest("%#v", nv5, "(*"+v5t+")"+"<nil>")
- addFormatterTest("%#+v", v5, "("+v5t+")"+v5s)
- addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s)
- addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s)
- addFormatterTest("%#+v", nv5, "(*"+v5t+")"+"<nil>")
-}
-
-func addUintFormatterTests() {
- // Max uint8.
- v := uint8(255)
- nv := (*uint8)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "uint8"
- vs := "255"
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%v", nv, "<nil>")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
-
- // Max uint16.
- v2 := uint16(65535)
- nv2 := (*uint16)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "uint16"
- v2s := "65535"
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s)
- addFormatterTest("%v", &pv2, "<**>"+v2s)
- addFormatterTest("%v", nv2, "<nil>")
- addFormatterTest("%+v", v2, v2s)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%+v", nv2, "<nil>")
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
- addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
-
- // Max uint32.
- v3 := uint32(4294967295)
- nv3 := (*uint32)(nil)
- pv3 := &v3
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "uint32"
- v3s := "4294967295"
- addFormatterTest("%v", v3, v3s)
- addFormatterTest("%v", pv3, "<*>"+v3s)
- addFormatterTest("%v", &pv3, "<**>"+v3s)
- addFormatterTest("%v", nv3, "<nil>")
- addFormatterTest("%+v", v3, v3s)
- addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
- addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
- addFormatterTest("%+v", nv3, "<nil>")
- addFormatterTest("%#v", v3, "("+v3t+")"+v3s)
- addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s)
- addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s)
- addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
- addFormatterTest("%#+v", v3, "("+v3t+")"+v3s)
- addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s)
- addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s)
- addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
-
- // Max uint64.
- v4 := uint64(18446744073709551615)
- nv4 := (*uint64)(nil)
- pv4 := &v4
- v4Addr := fmt.Sprintf("%p", pv4)
- pv4Addr := fmt.Sprintf("%p", &pv4)
- v4t := "uint64"
- v4s := "18446744073709551615"
- addFormatterTest("%v", v4, v4s)
- addFormatterTest("%v", pv4, "<*>"+v4s)
- addFormatterTest("%v", &pv4, "<**>"+v4s)
- addFormatterTest("%v", nv4, "<nil>")
- addFormatterTest("%+v", v4, v4s)
- addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
- addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
- addFormatterTest("%+v", nv4, "<nil>")
- addFormatterTest("%#v", v4, "("+v4t+")"+v4s)
- addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s)
- addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s)
- addFormatterTest("%#v", nv4, "(*"+v4t+")"+"<nil>")
- addFormatterTest("%#+v", v4, "("+v4t+")"+v4s)
- addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s)
- addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s)
- addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"<nil>")
-
- // Max uint.
- v5 := uint(4294967295)
- nv5 := (*uint)(nil)
- pv5 := &v5
- v5Addr := fmt.Sprintf("%p", pv5)
- pv5Addr := fmt.Sprintf("%p", &pv5)
- v5t := "uint"
- v5s := "4294967295"
- addFormatterTest("%v", v5, v5s)
- addFormatterTest("%v", pv5, "<*>"+v5s)
- addFormatterTest("%v", &pv5, "<**>"+v5s)
- addFormatterTest("%v", nv5, "<nil>")
- addFormatterTest("%+v", v5, v5s)
- addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s)
- addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s)
- addFormatterTest("%+v", nv5, "<nil>")
- addFormatterTest("%#v", v5, "("+v5t+")"+v5s)
- addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s)
- addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s)
- addFormatterTest("%#v", nv5, "(*"+v5t+")"+"<nil>")
- addFormatterTest("%#+v", v5, "("+v5t+")"+v5s)
- addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s)
- addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s)
- addFormatterTest("%#v", nv5, "(*"+v5t+")"+"<nil>")
-}
-
-func addBoolFormatterTests() {
- // Boolean true.
- v := bool(true)
- nv := (*bool)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "bool"
- vs := "true"
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%v", nv, "<nil>")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
-
- // Boolean false.
- v2 := bool(false)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "bool"
- v2s := "false"
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s)
- addFormatterTest("%v", &pv2, "<**>"+v2s)
- addFormatterTest("%+v", v2, v2s)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
-}
-
-func addFloatFormatterTests() {
- // Standard float32.
- v := float32(3.1415)
- nv := (*float32)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "float32"
- vs := "3.1415"
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%v", nv, "<nil>")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
-
- // Standard float64.
- v2 := float64(3.1415926)
- nv2 := (*float64)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "float64"
- v2s := "3.1415926"
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s)
- addFormatterTest("%v", &pv2, "<**>"+v2s)
- addFormatterTest("%+v", nv2, "<nil>")
- addFormatterTest("%+v", v2, v2s)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%+v", nv2, "<nil>")
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
- addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
-}
-
-func addComplexFormatterTests() {
- // Standard complex64.
- v := complex(float32(6), -2)
- nv := (*complex64)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "complex64"
- vs := "(6-2i)"
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
-
- // Standard complex128.
- v2 := complex(float64(-6), 2)
- nv2 := (*complex128)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "complex128"
- v2s := "(-6+2i)"
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s)
- addFormatterTest("%v", &pv2, "<**>"+v2s)
- addFormatterTest("%+v", nv2, "<nil>")
- addFormatterTest("%+v", v2, v2s)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%+v", nv2, "<nil>")
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
- addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
-}
-
-func addArrayFormatterTests() {
- // Array containing standard ints.
- v := [3]int{1, 2, 3}
- nv := (*[3]int)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "[3]int"
- vs := "[1 2 3]"
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
-
- // Array containing type with custom formatter on pointer receiver only.
- v2 := [3]pstringer{"1", "2", "3"}
- nv2 := (*[3]pstringer)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "[3]spew_test.pstringer"
- v2s := "[stringer 1 stringer 2 stringer 3]"
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s)
- addFormatterTest("%v", &pv2, "<**>"+v2s)
- addFormatterTest("%+v", nv2, "<nil>")
- addFormatterTest("%+v", v2, v2s)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%+v", nv2, "<nil>")
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
- addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
-
- // Array containing interfaces.
- v3 := [3]interface{}{"one", int(2), uint(3)}
- nv3 := (*[3]interface{})(nil)
- pv3 := &v3
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "[3]interface {}"
- v3t2 := "string"
- v3t3 := "int"
- v3t4 := "uint"
- v3s := "[one 2 3]"
- v3s2 := "[(" + v3t2 + ")one (" + v3t3 + ")2 (" + v3t4 + ")3]"
- addFormatterTest("%v", v3, v3s)
- addFormatterTest("%v", pv3, "<*>"+v3s)
- addFormatterTest("%v", &pv3, "<**>"+v3s)
- addFormatterTest("%+v", nv3, "<nil>")
- addFormatterTest("%+v", v3, v3s)
- addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
- addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
- addFormatterTest("%+v", nv3, "<nil>")
- addFormatterTest("%#v", v3, "("+v3t+")"+v3s2)
- addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2)
- addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2)
- addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
- addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2)
- addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2)
- addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2)
- addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"<nil>")
-}
-
-func addSliceFormatterTests() {
- // Slice containing standard float32 values.
- v := []float32{3.14, 6.28, 12.56}
- nv := (*[]float32)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "[]float32"
- vs := "[3.14 6.28 12.56]"
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
-
- // Slice containing type with custom formatter on pointer receiver only.
- v2 := []pstringer{"1", "2", "3"}
- nv2 := (*[]pstringer)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "[]spew_test.pstringer"
- v2s := "[stringer 1 stringer 2 stringer 3]"
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s)
- addFormatterTest("%v", &pv2, "<**>"+v2s)
- addFormatterTest("%+v", nv2, "<nil>")
- addFormatterTest("%+v", v2, v2s)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%+v", nv2, "<nil>")
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
- addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
-
- // Slice containing interfaces.
- v3 := []interface{}{"one", int(2), uint(3), nil}
- nv3 := (*[]interface{})(nil)
- pv3 := &v3
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "[]interface {}"
- v3t2 := "string"
- v3t3 := "int"
- v3t4 := "uint"
- v3t5 := "interface {}"
- v3s := "[one 2 3 <nil>]"
- v3s2 := "[(" + v3t2 + ")one (" + v3t3 + ")2 (" + v3t4 + ")3 (" + v3t5 +
- ")<nil>]"
- addFormatterTest("%v", v3, v3s)
- addFormatterTest("%v", pv3, "<*>"+v3s)
- addFormatterTest("%v", &pv3, "<**>"+v3s)
- addFormatterTest("%+v", nv3, "<nil>")
- addFormatterTest("%+v", v3, v3s)
- addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
- addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
- addFormatterTest("%+v", nv3, "<nil>")
- addFormatterTest("%#v", v3, "("+v3t+")"+v3s2)
- addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2)
- addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2)
- addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
- addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2)
- addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2)
- addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2)
- addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"<nil>")
-
- // Nil slice.
- var v4 []int
- nv4 := (*[]int)(nil)
- pv4 := &v4
- v4Addr := fmt.Sprintf("%p", pv4)
- pv4Addr := fmt.Sprintf("%p", &pv4)
- v4t := "[]int"
- v4s := "<nil>"
- addFormatterTest("%v", v4, v4s)
- addFormatterTest("%v", pv4, "<*>"+v4s)
- addFormatterTest("%v", &pv4, "<**>"+v4s)
- addFormatterTest("%+v", nv4, "<nil>")
- addFormatterTest("%+v", v4, v4s)
- addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
- addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
- addFormatterTest("%+v", nv4, "<nil>")
- addFormatterTest("%#v", v4, "("+v4t+")"+v4s)
- addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s)
- addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s)
- addFormatterTest("%#v", nv4, "(*"+v4t+")"+"<nil>")
- addFormatterTest("%#+v", v4, "("+v4t+")"+v4s)
- addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s)
- addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s)
- addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"<nil>")
-}
-
-func addStringFormatterTests() {
- // Standard string.
- v := "test"
- nv := (*string)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "string"
- vs := "test"
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
-}
-
-func addInterfaceFormatterTests() {
- // Nil interface.
- var v interface{}
- nv := (*interface{})(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "interface {}"
- vs := "<nil>"
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
-
- // Sub-interface.
- v2 := interface{}(uint16(65535))
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "uint16"
- v2s := "65535"
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s)
- addFormatterTest("%v", &pv2, "<**>"+v2s)
- addFormatterTest("%+v", v2, v2s)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
-}
-
-func addMapFormatterTests() {
- // Map with string keys and int vals.
- v := map[string]int{"one": 1, "two": 2}
- nilMap := map[string]int(nil)
- nv := (*map[string]int)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "map[string]int"
- vs := "map[one:1 two:2]"
- vs2 := "map[two:2 one:1]"
- addFormatterTest("%v", v, vs, vs2)
- addFormatterTest("%v", pv, "<*>"+vs, "<*>"+vs2)
- addFormatterTest("%v", &pv, "<**>"+vs, "<**>"+vs2)
- addFormatterTest("%+v", nilMap, "<nil>")
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%+v", v, vs, vs2)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs, "<*>("+vAddr+")"+vs2)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs,
- "<**>("+pvAddr+"->"+vAddr+")"+vs2)
- addFormatterTest("%+v", nilMap, "<nil>")
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%#v", v, "("+vt+")"+vs, "("+vt+")"+vs2)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs, "(*"+vt+")"+vs2)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs, "(**"+vt+")"+vs2)
- addFormatterTest("%#v", nilMap, "("+vt+")"+"<nil>")
- addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
- addFormatterTest("%#+v", v, "("+vt+")"+vs, "("+vt+")"+vs2)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs,
- "(*"+vt+")("+vAddr+")"+vs2)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs,
- "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs2)
- addFormatterTest("%#+v", nilMap, "("+vt+")"+"<nil>")
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
-
- // Map with custom formatter type on pointer receiver only keys and vals.
- v2 := map[pstringer]pstringer{"one": "1"}
- nv2 := (*map[pstringer]pstringer)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "map[spew_test.pstringer]spew_test.pstringer"
- v2s := "map[stringer one:stringer 1]"
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s)
- addFormatterTest("%v", &pv2, "<**>"+v2s)
- addFormatterTest("%+v", nv2, "<nil>")
- addFormatterTest("%+v", v2, v2s)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%+v", nv2, "<nil>")
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
- addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
-
- // Map with interface keys and values.
- v3 := map[interface{}]interface{}{"one": 1}
- nv3 := (*map[interface{}]interface{})(nil)
- pv3 := &v3
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "map[interface {}]interface {}"
- v3t1 := "string"
- v3t2 := "int"
- v3s := "map[one:1]"
- v3s2 := "map[(" + v3t1 + ")one:(" + v3t2 + ")1]"
- addFormatterTest("%v", v3, v3s)
- addFormatterTest("%v", pv3, "<*>"+v3s)
- addFormatterTest("%v", &pv3, "<**>"+v3s)
- addFormatterTest("%+v", nv3, "<nil>")
- addFormatterTest("%+v", v3, v3s)
- addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
- addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
- addFormatterTest("%+v", nv3, "<nil>")
- addFormatterTest("%#v", v3, "("+v3t+")"+v3s2)
- addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2)
- addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2)
- addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
- addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2)
- addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2)
- addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2)
- addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"<nil>")
-
- // Map with nil interface value
- v4 := map[string]interface{}{"nil": nil}
- nv4 := (*map[string]interface{})(nil)
- pv4 := &v4
- v4Addr := fmt.Sprintf("%p", pv4)
- pv4Addr := fmt.Sprintf("%p", &pv4)
- v4t := "map[string]interface {}"
- v4t1 := "interface {}"
- v4s := "map[nil:<nil>]"
- v4s2 := "map[nil:(" + v4t1 + ")<nil>]"
- addFormatterTest("%v", v4, v4s)
- addFormatterTest("%v", pv4, "<*>"+v4s)
- addFormatterTest("%v", &pv4, "<**>"+v4s)
- addFormatterTest("%+v", nv4, "<nil>")
- addFormatterTest("%+v", v4, v4s)
- addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
- addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
- addFormatterTest("%+v", nv4, "<nil>")
- addFormatterTest("%#v", v4, "("+v4t+")"+v4s2)
- addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s2)
- addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s2)
- addFormatterTest("%#v", nv4, "(*"+v4t+")"+"<nil>")
- addFormatterTest("%#+v", v4, "("+v4t+")"+v4s2)
- addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s2)
- addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s2)
- addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"<nil>")
-}
-
-func addStructFormatterTests() {
- // Struct with primitives.
- type s1 struct {
- a int8
- b uint8
- }
- v := s1{127, 255}
- nv := (*s1)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "spew_test.s1"
- vt2 := "int8"
- vt3 := "uint8"
- vs := "{127 255}"
- vs2 := "{a:127 b:255}"
- vs3 := "{a:(" + vt2 + ")127 b:(" + vt3 + ")255}"
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%+v", v, vs2)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs2)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs2)
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%#v", v, "("+vt+")"+vs3)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs3)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs3)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
- addFormatterTest("%#+v", v, "("+vt+")"+vs3)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs3)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs3)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
-
- // Struct that contains another struct.
- type s2 struct {
- s1 s1
- b bool
- }
- v2 := s2{s1{127, 255}, true}
- nv2 := (*s2)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "spew_test.s2"
- v2t2 := "spew_test.s1"
- v2t3 := "int8"
- v2t4 := "uint8"
- v2t5 := "bool"
- v2s := "{{127 255} true}"
- v2s2 := "{s1:{a:127 b:255} b:true}"
- v2s3 := "{s1:(" + v2t2 + "){a:(" + v2t3 + ")127 b:(" + v2t4 + ")255} b:(" +
- v2t5 + ")true}"
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s)
- addFormatterTest("%v", &pv2, "<**>"+v2s)
- addFormatterTest("%+v", nv2, "<nil>")
- addFormatterTest("%+v", v2, v2s2)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s2)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s2)
- addFormatterTest("%+v", nv2, "<nil>")
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s3)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s3)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s3)
- addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s3)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s3)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s3)
- addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
-
- // Struct that contains custom type with Stringer pointer interface via both
- // exported and unexported fields.
- type s3 struct {
- s pstringer
- S pstringer
- }
- v3 := s3{"test", "test2"}
- nv3 := (*s3)(nil)
- pv3 := &v3
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "spew_test.s3"
- v3t2 := "spew_test.pstringer"
- v3s := "{stringer test stringer test2}"
- v3s2 := "{s:stringer test S:stringer test2}"
- v3s3 := "{s:(" + v3t2 + ")stringer test S:(" + v3t2 + ")stringer test2}"
- addFormatterTest("%v", v3, v3s)
- addFormatterTest("%v", pv3, "<*>"+v3s)
- addFormatterTest("%v", &pv3, "<**>"+v3s)
- addFormatterTest("%+v", nv3, "<nil>")
- addFormatterTest("%+v", v3, v3s2)
- addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s2)
- addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s2)
- addFormatterTest("%+v", nv3, "<nil>")
- addFormatterTest("%#v", v3, "("+v3t+")"+v3s3)
- addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s3)
- addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s3)
- addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
- addFormatterTest("%#+v", v3, "("+v3t+")"+v3s3)
- addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s3)
- addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s3)
- addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"<nil>")
-
- // Struct that contains embedded struct and field to same struct.
- e := embed{"embedstr"}
- v4 := embedwrap{embed: &e, e: &e}
- nv4 := (*embedwrap)(nil)
- pv4 := &v4
- eAddr := fmt.Sprintf("%p", &e)
- v4Addr := fmt.Sprintf("%p", pv4)
- pv4Addr := fmt.Sprintf("%p", &pv4)
- v4t := "spew_test.embedwrap"
- v4t2 := "spew_test.embed"
- v4t3 := "string"
- v4s := "{<*>{embedstr} <*>{embedstr}}"
- v4s2 := "{embed:<*>(" + eAddr + "){a:embedstr} e:<*>(" + eAddr +
- "){a:embedstr}}"
- v4s3 := "{embed:(*" + v4t2 + "){a:(" + v4t3 + ")embedstr} e:(*" + v4t2 +
- "){a:(" + v4t3 + ")embedstr}}"
- v4s4 := "{embed:(*" + v4t2 + ")(" + eAddr + "){a:(" + v4t3 +
- ")embedstr} e:(*" + v4t2 + ")(" + eAddr + "){a:(" + v4t3 + ")embedstr}}"
- addFormatterTest("%v", v4, v4s)
- addFormatterTest("%v", pv4, "<*>"+v4s)
- addFormatterTest("%v", &pv4, "<**>"+v4s)
- addFormatterTest("%+v", nv4, "<nil>")
- addFormatterTest("%+v", v4, v4s2)
- addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s2)
- addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s2)
- addFormatterTest("%+v", nv4, "<nil>")
- addFormatterTest("%#v", v4, "("+v4t+")"+v4s3)
- addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s3)
- addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s3)
- addFormatterTest("%#v", nv4, "(*"+v4t+")"+"<nil>")
- addFormatterTest("%#+v", v4, "("+v4t+")"+v4s4)
- addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s4)
- addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s4)
- addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"<nil>")
-}
-
-func addUintptrFormatterTests() {
- // Null pointer.
- v := uintptr(0)
- nv := (*uintptr)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "uintptr"
- vs := "<nil>"
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
-
- // Address of real variable.
- i := 1
- v2 := uintptr(unsafe.Pointer(&i))
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "uintptr"
- v2s := fmt.Sprintf("%p", &i)
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s)
- addFormatterTest("%v", &pv2, "<**>"+v2s)
- addFormatterTest("%+v", v2, v2s)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
-}
-
-func addUnsafePointerFormatterTests() {
- // Null pointer.
- v := unsafe.Pointer(uintptr(0))
- nv := (*unsafe.Pointer)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "unsafe.Pointer"
- vs := "<nil>"
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
-
- // Address of real variable.
- i := 1
- v2 := unsafe.Pointer(&i)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "unsafe.Pointer"
- v2s := fmt.Sprintf("%p", &i)
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s)
- addFormatterTest("%v", &pv2, "<**>"+v2s)
- addFormatterTest("%+v", v2, v2s)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
-}
-
-func addChanFormatterTests() {
- // Nil channel.
- var v chan int
- pv := &v
- nv := (*chan int)(nil)
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "chan int"
- vs := "<nil>"
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
-
- // Real channel.
- v2 := make(chan int)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "chan int"
- v2s := fmt.Sprintf("%p", v2)
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s)
- addFormatterTest("%v", &pv2, "<**>"+v2s)
- addFormatterTest("%+v", v2, v2s)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
-}
-
-func addFuncFormatterTests() {
- // Function with no params and no returns.
- v := addIntFormatterTests
- nv := (*func())(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "func()"
- vs := fmt.Sprintf("%p", v)
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
-
- // Function with param and no returns.
- v2 := TestFormatter
- nv2 := (*func(*testing.T))(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "func(*testing.T)"
- v2s := fmt.Sprintf("%p", v2)
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s)
- addFormatterTest("%v", &pv2, "<**>"+v2s)
- addFormatterTest("%+v", nv2, "<nil>")
- addFormatterTest("%+v", v2, v2s)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%+v", nv2, "<nil>")
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
- addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
-
- // Function with multiple params and multiple returns.
- var v3 = func(i int, s string) (b bool, err error) {
- return true, nil
- }
- nv3 := (*func(int, string) (bool, error))(nil)
- pv3 := &v3
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "func(int, string) (bool, error)"
- v3s := fmt.Sprintf("%p", v3)
- addFormatterTest("%v", v3, v3s)
- addFormatterTest("%v", pv3, "<*>"+v3s)
- addFormatterTest("%v", &pv3, "<**>"+v3s)
- addFormatterTest("%+v", nv3, "<nil>")
- addFormatterTest("%+v", v3, v3s)
- addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
- addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
- addFormatterTest("%+v", nv3, "<nil>")
- addFormatterTest("%#v", v3, "("+v3t+")"+v3s)
- addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s)
- addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s)
- addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
- addFormatterTest("%#+v", v3, "("+v3t+")"+v3s)
- addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s)
- addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s)
- addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"<nil>")
-}
-
-func addCircularFormatterTests() {
- // Struct that is circular through self referencing.
- type circular struct {
- c *circular
- }
- v := circular{nil}
- v.c = &v
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "spew_test.circular"
- vs := "{<*>{<*><shown>}}"
- vs2 := "{<*><shown>}"
- vs3 := "{c:<*>(" + vAddr + "){c:<*>(" + vAddr + ")<shown>}}"
- vs4 := "{c:<*>(" + vAddr + ")<shown>}"
- vs5 := "{c:(*" + vt + "){c:(*" + vt + ")<shown>}}"
- vs6 := "{c:(*" + vt + ")<shown>}"
- vs7 := "{c:(*" + vt + ")(" + vAddr + "){c:(*" + vt + ")(" + vAddr +
- ")<shown>}}"
- vs8 := "{c:(*" + vt + ")(" + vAddr + ")<shown>}"
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs2)
- addFormatterTest("%v", &pv, "<**>"+vs2)
- addFormatterTest("%+v", v, vs3)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs4)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs4)
- addFormatterTest("%#v", v, "("+vt+")"+vs5)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs6)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs6)
- addFormatterTest("%#+v", v, "("+vt+")"+vs7)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs8)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs8)
-
- // Structs that are circular through cross referencing.
- v2 := xref1{nil}
- ts2 := xref2{&v2}
- v2.ps2 = &ts2
- pv2 := &v2
- ts2Addr := fmt.Sprintf("%p", &ts2)
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "spew_test.xref1"
- v2t2 := "spew_test.xref2"
- v2s := "{<*>{<*>{<*><shown>}}}"
- v2s2 := "{<*>{<*><shown>}}"
- v2s3 := "{ps2:<*>(" + ts2Addr + "){ps1:<*>(" + v2Addr + "){ps2:<*>(" +
- ts2Addr + ")<shown>}}}"
- v2s4 := "{ps2:<*>(" + ts2Addr + "){ps1:<*>(" + v2Addr + ")<shown>}}"
- v2s5 := "{ps2:(*" + v2t2 + "){ps1:(*" + v2t + "){ps2:(*" + v2t2 +
- ")<shown>}}}"
- v2s6 := "{ps2:(*" + v2t2 + "){ps1:(*" + v2t + ")<shown>}}"
- v2s7 := "{ps2:(*" + v2t2 + ")(" + ts2Addr + "){ps1:(*" + v2t +
- ")(" + v2Addr + "){ps2:(*" + v2t2 + ")(" + ts2Addr +
- ")<shown>}}}"
- v2s8 := "{ps2:(*" + v2t2 + ")(" + ts2Addr + "){ps1:(*" + v2t +
- ")(" + v2Addr + ")<shown>}}"
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s2)
- addFormatterTest("%v", &pv2, "<**>"+v2s2)
- addFormatterTest("%+v", v2, v2s3)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s4)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s4)
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s5)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s6)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s6)
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s7)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s8)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s8)
-
- // Structs that are indirectly circular.
- v3 := indirCir1{nil}
- tic2 := indirCir2{nil}
- tic3 := indirCir3{&v3}
- tic2.ps3 = &tic3
- v3.ps2 = &tic2
- pv3 := &v3
- tic2Addr := fmt.Sprintf("%p", &tic2)
- tic3Addr := fmt.Sprintf("%p", &tic3)
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "spew_test.indirCir1"
- v3t2 := "spew_test.indirCir2"
- v3t3 := "spew_test.indirCir3"
- v3s := "{<*>{<*>{<*>{<*><shown>}}}}"
- v3s2 := "{<*>{<*>{<*><shown>}}}"
- v3s3 := "{ps2:<*>(" + tic2Addr + "){ps3:<*>(" + tic3Addr + "){ps1:<*>(" +
- v3Addr + "){ps2:<*>(" + tic2Addr + ")<shown>}}}}"
- v3s4 := "{ps2:<*>(" + tic2Addr + "){ps3:<*>(" + tic3Addr + "){ps1:<*>(" +
- v3Addr + ")<shown>}}}"
- v3s5 := "{ps2:(*" + v3t2 + "){ps3:(*" + v3t3 + "){ps1:(*" + v3t +
- "){ps2:(*" + v3t2 + ")<shown>}}}}"
- v3s6 := "{ps2:(*" + v3t2 + "){ps3:(*" + v3t3 + "){ps1:(*" + v3t +
- ")<shown>}}}"
- v3s7 := "{ps2:(*" + v3t2 + ")(" + tic2Addr + "){ps3:(*" + v3t3 + ")(" +
- tic3Addr + "){ps1:(*" + v3t + ")(" + v3Addr + "){ps2:(*" + v3t2 +
- ")(" + tic2Addr + ")<shown>}}}}"
- v3s8 := "{ps2:(*" + v3t2 + ")(" + tic2Addr + "){ps3:(*" + v3t3 + ")(" +
- tic3Addr + "){ps1:(*" + v3t + ")(" + v3Addr + ")<shown>}}}"
- addFormatterTest("%v", v3, v3s)
- addFormatterTest("%v", pv3, "<*>"+v3s2)
- addFormatterTest("%v", &pv3, "<**>"+v3s2)
- addFormatterTest("%+v", v3, v3s3)
- addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s4)
- addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s4)
- addFormatterTest("%#v", v3, "("+v3t+")"+v3s5)
- addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s6)
- addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s6)
- addFormatterTest("%#+v", v3, "("+v3t+")"+v3s7)
- addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s8)
- addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s8)
-}
-
-func addPanicFormatterTests() {
- // Type that panics in its Stringer interface.
- v := panicer(127)
- nv := (*panicer)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "spew_test.panicer"
- vs := "(PANIC=test panic)127"
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%v", nv, "<nil>")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
-}
-
-func addErrorFormatterTests() {
- // Type that has a custom Error interface.
- v := customError(127)
- nv := (*customError)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "spew_test.customError"
- vs := "error: 127"
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%v", nv, "<nil>")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "<nil>")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
-}
-
-func addPassthroughFormatterTests() {
- // %x passthrough with uint.
- v := uint(4294967295)
- pv := &v
- vAddr := fmt.Sprintf("%x", pv)
- pvAddr := fmt.Sprintf("%x", &pv)
- vs := "ffffffff"
- addFormatterTest("%x", v, vs)
- addFormatterTest("%x", pv, vAddr)
- addFormatterTest("%x", &pv, pvAddr)
-
- // %#x passthrough with uint.
- v2 := int(2147483647)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%#x", pv2)
- pv2Addr := fmt.Sprintf("%#x", &pv2)
- v2s := "0x7fffffff"
- addFormatterTest("%#x", v2, v2s)
- addFormatterTest("%#x", pv2, v2Addr)
- addFormatterTest("%#x", &pv2, pv2Addr)
-
- // %f passthrough with precision.
- addFormatterTest("%.2f", 3.1415, "3.14")
- addFormatterTest("%.3f", 3.1415, "3.142")
- addFormatterTest("%.4f", 3.1415, "3.1415")
-
- // %f passthrough with width and precision.
- addFormatterTest("%5.2f", 3.1415, " 3.14")
- addFormatterTest("%6.3f", 3.1415, " 3.142")
- addFormatterTest("%7.4f", 3.1415, " 3.1415")
-
- // %d passthrough with width.
- addFormatterTest("%3d", 127, "127")
- addFormatterTest("%4d", 127, " 127")
- addFormatterTest("%5d", 127, " 127")
-
- // %q passthrough with string.
- addFormatterTest("%q", "test", "\"test\"")
-}
-
-// TestFormatter executes all of the tests described by formatterTests.
-func TestFormatter(t *testing.T) {
- // Setup tests.
- addIntFormatterTests()
- addUintFormatterTests()
- addBoolFormatterTests()
- addFloatFormatterTests()
- addComplexFormatterTests()
- addArrayFormatterTests()
- addSliceFormatterTests()
- addStringFormatterTests()
- addInterfaceFormatterTests()
- addMapFormatterTests()
- addStructFormatterTests()
- addUintptrFormatterTests()
- addUnsafePointerFormatterTests()
- addChanFormatterTests()
- addFuncFormatterTests()
- addCircularFormatterTests()
- addPanicFormatterTests()
- addErrorFormatterTests()
- addPassthroughFormatterTests()
-
- t.Logf("Running %d tests", len(formatterTests))
- for i, test := range formatterTests {
- buf := new(bytes.Buffer)
- spew.Fprintf(buf, test.format, test.in)
- s := buf.String()
- if testFailed(s, test.wants) {
- t.Errorf("Formatter #%d format: %s got: %s %s", i, test.format, s,
- stringizeWants(test.wants))
- continue
- }
- }
-}
-
-type testStruct struct {
- x int
-}
-
-func (ts testStruct) String() string {
- return fmt.Sprintf("ts.%d", ts.x)
-}
-
-type testStructP struct {
- x int
-}
-
-func (ts *testStructP) String() string {
- return fmt.Sprintf("ts.%d", ts.x)
-}
-
-func TestPrintSortedKeys(t *testing.T) {
- cfg := spew.ConfigState{SortKeys: true}
- s := cfg.Sprint(map[int]string{1: "1", 3: "3", 2: "2"})
- expected := "map[1:1 2:2 3:3]"
- if s != expected {
- t.Errorf("Sorted keys mismatch:\n %v %v", s, expected)
- }
-
- s = cfg.Sprint(map[stringer]int{"1": 1, "3": 3, "2": 2})
- expected = "map[stringer 1:1 stringer 2:2 stringer 3:3]"
- if s != expected {
- t.Errorf("Sorted keys mismatch:\n %v %v", s, expected)
- }
-
- s = cfg.Sprint(map[pstringer]int{pstringer("1"): 1, pstringer("3"): 3, pstringer("2"): 2})
- expected = "map[stringer 1:1 stringer 2:2 stringer 3:3]"
- if s != expected {
- t.Errorf("Sorted keys mismatch:\n %v %v", s, expected)
- }
-
- s = cfg.Sprint(map[testStruct]int{testStruct{1}: 1, testStruct{3}: 3, testStruct{2}: 2})
- expected = "map[ts.1:1 ts.2:2 ts.3:3]"
- if s != expected {
- t.Errorf("Sorted keys mismatch:\n %v %v", s, expected)
- }
-
- s = cfg.Sprint(map[testStructP]int{testStructP{1}: 1, testStructP{3}: 3, testStructP{2}: 2})
- expected = "map[ts.1:1 ts.2:2 ts.3:3]"
- if s != expected {
- t.Errorf("Sorted keys mismatch:\n %v %v", s, expected)
- }
-
- s = cfg.Sprint(map[customError]int{customError(1): 1, customError(3): 3, customError(2): 2})
- expected = "map[error: 1:1 error: 2:2 error: 3:3]"
- if s != expected {
- t.Errorf("Sorted keys mismatch:\n %v %v", s, expected)
- }
-}
diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/internal_test.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/internal_test.go
deleted file mode 100644
index b583bfdef..000000000
--- a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/internal_test.go
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (c) 2013 Dave Collins <dave@davec.name>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-/*
-This test file is part of the spew package rather than than the spew_test
-package because it needs access to internals to properly test certain cases
-which are not possible via the public interface since they should never happen.
-*/
-
-package spew
-
-import (
- "bytes"
- "reflect"
- "testing"
- "unsafe"
-)
-
-// dummyFmtState implements a fake fmt.State to use for testing invalid
-// reflect.Value handling. This is necessary because the fmt package catches
-// invalid values before invoking the formatter on them.
-type dummyFmtState struct {
- bytes.Buffer
-}
-
-func (dfs *dummyFmtState) Flag(f int) bool {
- if f == int('+') {
- return true
- }
- return false
-}
-
-func (dfs *dummyFmtState) Precision() (int, bool) {
- return 0, false
-}
-
-func (dfs *dummyFmtState) Width() (int, bool) {
- return 0, false
-}
-
-// TestInvalidReflectValue ensures the dump and formatter code handles an
-// invalid reflect value properly. This needs access to internal state since it
-// should never happen in real code and therefore can't be tested via the public
-// API.
-func TestInvalidReflectValue(t *testing.T) {
- i := 1
-
- // Dump invalid reflect value.
- v := new(reflect.Value)
- buf := new(bytes.Buffer)
- d := dumpState{w: buf, cs: &Config}
- d.dump(*v)
- s := buf.String()
- want := "<invalid>"
- if s != want {
- t.Errorf("InvalidReflectValue #%d\n got: %s want: %s", i, s, want)
- }
- i++
-
- // Formatter invalid reflect value.
- buf2 := new(dummyFmtState)
- f := formatState{value: *v, cs: &Config, fs: buf2}
- f.format(*v)
- s = buf2.String()
- want = "<invalid>"
- if s != want {
- t.Errorf("InvalidReflectValue #%d got: %s want: %s", i, s, want)
- }
-}
-
-// changeKind uses unsafe to intentionally change the kind of a reflect.Value to
-// the maximum kind value which does not exist. This is needed to test the
-// fallback code which punts to the standard fmt library for new types that
-// might get added to the language.
-func changeKind(v *reflect.Value, readOnly bool) {
- rvf := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + offsetFlag))
- *rvf = *rvf | ((1<<flagKindWidth - 1) << flagKindShift)
- if readOnly {
- *rvf |= flagRO
- } else {
- *rvf &= ^uintptr(flagRO)
- }
-}
-
-// TestAddedReflectValue tests functionaly of the dump and formatter code which
-// falls back to the standard fmt library for new types that might get added to
-// the language.
-func TestAddedReflectValue(t *testing.T) {
- i := 1
-
- // Dump using a reflect.Value that is exported.
- v := reflect.ValueOf(int8(5))
- changeKind(&v, false)
- buf := new(bytes.Buffer)
- d := dumpState{w: buf, cs: &Config}
- d.dump(v)
- s := buf.String()
- want := "(int8) 5"
- if s != want {
- t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want)
- }
- i++
-
- // Dump using a reflect.Value that is not exported.
- changeKind(&v, true)
- buf.Reset()
- d.dump(v)
- s = buf.String()
- want = "(int8) <int8 Value>"
- if s != want {
- t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want)
- }
- i++
-
- // Formatter using a reflect.Value that is exported.
- changeKind(&v, false)
- buf2 := new(dummyFmtState)
- f := formatState{value: v, cs: &Config, fs: buf2}
- f.format(v)
- s = buf2.String()
- want = "5"
- if s != want {
- t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want)
- }
- i++
-
- // Formatter using a reflect.Value that is not exported.
- changeKind(&v, true)
- buf2.Reset()
- f = formatState{value: v, cs: &Config, fs: buf2}
- f.format(v)
- s = buf2.String()
- want = "<int8 Value>"
- if s != want {
- t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want)
- }
-}
-
-// SortValues makes the internal sortValues function available to the test
-// package.
-func SortValues(values []reflect.Value, cs *ConfigState) {
- sortValues(values, cs)
-}
diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/spew_test.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/spew_test.go
deleted file mode 100644
index 3831ed2fb..000000000
--- a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/spew_test.go
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * Copyright (c) 2013 Dave Collins <dave@davec.name>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-package spew_test
-
-import (
- "bytes"
- "fmt"
- "github.com/davecgh/go-spew/spew"
- "io/ioutil"
- "os"
- "testing"
-)
-
-// spewFunc is used to identify which public function of the spew package or
-// ConfigState a test applies to.
-type spewFunc int
-
-const (
- fCSFdump spewFunc = iota
- fCSFprint
- fCSFprintf
- fCSFprintln
- fCSPrint
- fCSPrintln
- fCSSdump
- fCSSprint
- fCSSprintf
- fCSSprintln
- fCSErrorf
- fCSNewFormatter
- fErrorf
- fFprint
- fFprintln
- fPrint
- fPrintln
- fSdump
- fSprint
- fSprintf
- fSprintln
-)
-
-// Map of spewFunc values to names for pretty printing.
-var spewFuncStrings = map[spewFunc]string{
- fCSFdump: "ConfigState.Fdump",
- fCSFprint: "ConfigState.Fprint",
- fCSFprintf: "ConfigState.Fprintf",
- fCSFprintln: "ConfigState.Fprintln",
- fCSSdump: "ConfigState.Sdump",
- fCSPrint: "ConfigState.Print",
- fCSPrintln: "ConfigState.Println",
- fCSSprint: "ConfigState.Sprint",
- fCSSprintf: "ConfigState.Sprintf",
- fCSSprintln: "ConfigState.Sprintln",
- fCSErrorf: "ConfigState.Errorf",
- fCSNewFormatter: "ConfigState.NewFormatter",
- fErrorf: "spew.Errorf",
- fFprint: "spew.Fprint",
- fFprintln: "spew.Fprintln",
- fPrint: "spew.Print",
- fPrintln: "spew.Println",
- fSdump: "spew.Sdump",
- fSprint: "spew.Sprint",
- fSprintf: "spew.Sprintf",
- fSprintln: "spew.Sprintln",
-}
-
-func (f spewFunc) String() string {
- if s, ok := spewFuncStrings[f]; ok {
- return s
- }
- return fmt.Sprintf("Unknown spewFunc (%d)", int(f))
-}
-
-// spewTest is used to describe a test to be performed against the public
-// functions of the spew package or ConfigState.
-type spewTest struct {
- cs *spew.ConfigState
- f spewFunc
- format string
- in interface{}
- want string
-}
-
-// spewTests houses the tests to be performed against the public functions of
-// the spew package and ConfigState.
-//
-// These tests are only intended to ensure the public functions are exercised
-// and are intentionally not exhaustive of types. The exhaustive type
-// tests are handled in the dump and format tests.
-var spewTests []spewTest
-
-// redirStdout is a helper function to return the standard output from f as a
-// byte slice.
-func redirStdout(f func()) ([]byte, error) {
- tempFile, err := ioutil.TempFile("", "ss-test")
- if err != nil {
- return nil, err
- }
- fileName := tempFile.Name()
- defer os.Remove(fileName) // Ignore error
-
- origStdout := os.Stdout
- os.Stdout = tempFile
- f()
- os.Stdout = origStdout
- tempFile.Close()
-
- return ioutil.ReadFile(fileName)
-}
-
-func initSpewTests() {
- // Config states with various settings.
- scsDefault := spew.NewDefaultConfig()
- scsNoMethods := &spew.ConfigState{Indent: " ", DisableMethods: true}
- scsNoPmethods := &spew.ConfigState{Indent: " ", DisablePointerMethods: true}
- scsMaxDepth := &spew.ConfigState{Indent: " ", MaxDepth: 1}
- scsContinue := &spew.ConfigState{Indent: " ", ContinueOnMethod: true}
-
- // Variables for tests on types which implement Stringer interface with and
- // without a pointer receiver.
- ts := stringer("test")
- tps := pstringer("test")
-
- // depthTester is used to test max depth handling for structs, array, slices
- // and maps.
- type depthTester struct {
- ic indirCir1
- arr [1]string
- slice []string
- m map[string]int
- }
- dt := depthTester{indirCir1{nil}, [1]string{"arr"}, []string{"slice"},
- map[string]int{"one": 1}}
-
- // Variable for tests on types which implement error interface.
- te := customError(10)
-
- spewTests = []spewTest{
- {scsDefault, fCSFdump, "", int8(127), "(int8) 127\n"},
- {scsDefault, fCSFprint, "", int16(32767), "32767"},
- {scsDefault, fCSFprintf, "%v", int32(2147483647), "2147483647"},
- {scsDefault, fCSFprintln, "", int(2147483647), "2147483647\n"},
- {scsDefault, fCSPrint, "", int64(9223372036854775807), "9223372036854775807"},
- {scsDefault, fCSPrintln, "", uint8(255), "255\n"},
- {scsDefault, fCSSdump, "", uint8(64), "(uint8) 64\n"},
- {scsDefault, fCSSprint, "", complex(1, 2), "(1+2i)"},
- {scsDefault, fCSSprintf, "%v", complex(float32(3), 4), "(3+4i)"},
- {scsDefault, fCSSprintln, "", complex(float64(5), 6), "(5+6i)\n"},
- {scsDefault, fCSErrorf, "%#v", uint16(65535), "(uint16)65535"},
- {scsDefault, fCSNewFormatter, "%v", uint32(4294967295), "4294967295"},
- {scsDefault, fErrorf, "%v", uint64(18446744073709551615), "18446744073709551615"},
- {scsDefault, fFprint, "", float32(3.14), "3.14"},
- {scsDefault, fFprintln, "", float64(6.28), "6.28\n"},
- {scsDefault, fPrint, "", true, "true"},
- {scsDefault, fPrintln, "", false, "false\n"},
- {scsDefault, fSdump, "", complex(-10, -20), "(complex128) (-10-20i)\n"},
- {scsDefault, fSprint, "", complex(-1, -2), "(-1-2i)"},
- {scsDefault, fSprintf, "%v", complex(float32(-3), -4), "(-3-4i)"},
- {scsDefault, fSprintln, "", complex(float64(-5), -6), "(-5-6i)\n"},
- {scsNoMethods, fCSFprint, "", ts, "test"},
- {scsNoMethods, fCSFprint, "", &ts, "<*>test"},
- {scsNoMethods, fCSFprint, "", tps, "test"},
- {scsNoMethods, fCSFprint, "", &tps, "<*>test"},
- {scsNoPmethods, fCSFprint, "", ts, "stringer test"},
- {scsNoPmethods, fCSFprint, "", &ts, "<*>stringer test"},
- {scsNoPmethods, fCSFprint, "", tps, "test"},
- {scsNoPmethods, fCSFprint, "", &tps, "<*>stringer test"},
- {scsMaxDepth, fCSFprint, "", dt, "{{<max>} [<max>] [<max>] map[<max>]}"},
- {scsMaxDepth, fCSFdump, "", dt, "(spew_test.depthTester) {\n" +
- " ic: (spew_test.indirCir1) {\n <max depth reached>\n },\n" +
- " arr: ([1]string) (len=1 cap=1) {\n <max depth reached>\n },\n" +
- " slice: ([]string) (len=1 cap=1) {\n <max depth reached>\n },\n" +
- " m: (map[string]int) (len=1) {\n <max depth reached>\n }\n}\n"},
- {scsContinue, fCSFprint, "", ts, "(stringer test) test"},
- {scsContinue, fCSFdump, "", ts, "(spew_test.stringer) " +
- "(len=4) (stringer test) \"test\"\n"},
- {scsContinue, fCSFprint, "", te, "(error: 10) 10"},
- {scsContinue, fCSFdump, "", te, "(spew_test.customError) " +
- "(error: 10) 10\n"},
- }
-}
-
-// TestSpew executes all of the tests described by spewTests.
-func TestSpew(t *testing.T) {
- initSpewTests()
-
- t.Logf("Running %d tests", len(spewTests))
- for i, test := range spewTests {
- buf := new(bytes.Buffer)
- switch test.f {
- case fCSFdump:
- test.cs.Fdump(buf, test.in)
-
- case fCSFprint:
- test.cs.Fprint(buf, test.in)
-
- case fCSFprintf:
- test.cs.Fprintf(buf, test.format, test.in)
-
- case fCSFprintln:
- test.cs.Fprintln(buf, test.in)
-
- case fCSPrint:
- b, err := redirStdout(func() { test.cs.Print(test.in) })
- if err != nil {
- t.Errorf("%v #%d %v", test.f, i, err)
- continue
- }
- buf.Write(b)
-
- case fCSPrintln:
- b, err := redirStdout(func() { test.cs.Println(test.in) })
- if err != nil {
- t.Errorf("%v #%d %v", test.f, i, err)
- continue
- }
- buf.Write(b)
-
- case fCSSdump:
- str := test.cs.Sdump(test.in)
- buf.WriteString(str)
-
- case fCSSprint:
- str := test.cs.Sprint(test.in)
- buf.WriteString(str)
-
- case fCSSprintf:
- str := test.cs.Sprintf(test.format, test.in)
- buf.WriteString(str)
-
- case fCSSprintln:
- str := test.cs.Sprintln(test.in)
- buf.WriteString(str)
-
- case fCSErrorf:
- err := test.cs.Errorf(test.format, test.in)
- buf.WriteString(err.Error())
-
- case fCSNewFormatter:
- fmt.Fprintf(buf, test.format, test.cs.NewFormatter(test.in))
-
- case fErrorf:
- err := spew.Errorf(test.format, test.in)
- buf.WriteString(err.Error())
-
- case fFprint:
- spew.Fprint(buf, test.in)
-
- case fFprintln:
- spew.Fprintln(buf, test.in)
-
- case fPrint:
- b, err := redirStdout(func() { spew.Print(test.in) })
- if err != nil {
- t.Errorf("%v #%d %v", test.f, i, err)
- continue
- }
- buf.Write(b)
-
- case fPrintln:
- b, err := redirStdout(func() { spew.Println(test.in) })
- if err != nil {
- t.Errorf("%v #%d %v", test.f, i, err)
- continue
- }
- buf.Write(b)
-
- case fSdump:
- str := spew.Sdump(test.in)
- buf.WriteString(str)
-
- case fSprint:
- str := spew.Sprint(test.in)
- buf.WriteString(str)
-
- case fSprintf:
- str := spew.Sprintf(test.format, test.in)
- buf.WriteString(str)
-
- case fSprintln:
- str := spew.Sprintln(test.in)
- buf.WriteString(str)
-
- default:
- t.Errorf("%v #%d unrecognized function", test.f, i)
- continue
- }
- s := buf.String()
- if test.want != s {
- t.Errorf("ConfigState #%d\n got: %s want: %s", i, s, test.want)
- continue
- }
- }
-}
diff --git a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/testdata/dumpcgo.go b/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/testdata/dumpcgo.go
deleted file mode 100644
index 5c87dd456..000000000
--- a/Godeps/_workspace/src/github.com/davecgh/go-spew/spew/testdata/dumpcgo.go
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright (c) 2013 Dave Collins <dave@davec.name>
-//
-// Permission to use, copy, modify, and distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-// NOTE: Due to the following build constraints, this file will only be compiled
-// when both cgo is supported and "-tags testcgo" is added to the go test
-// command line. This code should really only be in the dumpcgo_test.go file,
-// but unfortunately Go will not allow cgo in test files, so this is a
-// workaround to allow cgo types to be tested. This configuration is used
-// because spew itself does not require cgo to run even though it does handle
-// certain cgo types specially. Rather than forcing all clients to require cgo
-// and an external C compiler just to run the tests, this scheme makes them
-// optional.
-// +build cgo,testcgo
-
-package testdata
-
-/*
-#include <stdint.h>
-typedef unsigned char custom_uchar_t;
-
-char *ncp = 0;
-char *cp = "test";
-char ca[6] = {'t', 'e', 's', 't', '2', '\0'};
-unsigned char uca[6] = {'t', 'e', 's', 't', '3', '\0'};
-signed char sca[6] = {'t', 'e', 's', 't', '4', '\0'};
-uint8_t ui8ta[6] = {'t', 'e', 's', 't', '5', '\0'};
-custom_uchar_t tuca[6] = {'t', 'e', 's', 't', '6', '\0'};
-*/
-import "C"
-
-// GetCgoNullCharPointer returns a null char pointer via cgo. This is only
-// used for tests.
-func GetCgoNullCharPointer() interface{} {
- return C.ncp
-}
-
-// GetCgoCharPointer returns a char pointer via cgo. This is only used for
-// tests.
-func GetCgoCharPointer() interface{} {
- return C.cp
-}
-
-// GetCgoCharArray returns a char array via cgo and the array's len and cap.
-// This is only used for tests.
-func GetCgoCharArray() (interface{}, int, int) {
- return C.ca, len(C.ca), cap(C.ca)
-}
-
-// GetCgoUnsignedCharArray returns an unsigned char array via cgo and the
-// array's len and cap. This is only used for tests.
-func GetCgoUnsignedCharArray() (interface{}, int, int) {
- return C.uca, len(C.uca), cap(C.uca)
-}
-
-// GetCgoSignedCharArray returns a signed char array via cgo and the array's len
-// and cap. This is only used for tests.
-func GetCgoSignedCharArray() (interface{}, int, int) {
- return C.sca, len(C.sca), cap(C.sca)
-}
-
-// GetCgoUint8tArray returns a uint8_t array via cgo and the array's len and
-// cap. This is only used for tests.
-func GetCgoUint8tArray() (interface{}, int, int) {
- return C.ui8ta, len(C.ui8ta), cap(C.ui8ta)
-}
-
-// GetCgoTypdefedUnsignedCharArray returns a typedefed unsigned char array via
-// cgo and the array's len and cap. This is only used for tests.
-func GetCgoTypdefedUnsignedCharArray() (interface{}, int, int) {
- return C.tuca, len(C.tuca), cap(C.tuca)
-}
diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/ethash_test.go b/Godeps/_workspace/src/github.com/ethereum/ethash/ethash_test.go
deleted file mode 100644
index e0ca0bd85..000000000
--- a/Godeps/_workspace/src/github.com/ethereum/ethash/ethash_test.go
+++ /dev/null
@@ -1,221 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// Copyright 2015 Lefteris Karapetsas <lefteris@refu.co>
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package ethash
-
-import (
- "bytes"
- "crypto/rand"
- "encoding/hex"
- "log"
- "math/big"
- "os"
- "sync"
- "testing"
-
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/crypto"
-)
-
-func init() {
- // glog.SetV(6)
- // glog.SetToStderr(true)
-}
-
-type testBlock struct {
- difficulty *big.Int
- hashNoNonce common.Hash
- nonce uint64
- mixDigest common.Hash
- number uint64
-}
-
-func (b *testBlock) Difficulty() *big.Int { return b.difficulty }
-func (b *testBlock) HashNoNonce() common.Hash { return b.hashNoNonce }
-func (b *testBlock) Nonce() uint64 { return b.nonce }
-func (b *testBlock) MixDigest() common.Hash { return b.mixDigest }
-func (b *testBlock) NumberU64() uint64 { return b.number }
-
-var validBlocks = []*testBlock{
- // from proof of concept nine testnet, epoch 0
- {
- number: 22,
- hashNoNonce: common.HexToHash("372eca2454ead349c3df0ab5d00b0b706b23e49d469387db91811cee0358fc6d"),
- difficulty: big.NewInt(132416),
- nonce: 0x495732e0ed7a801c,
- mixDigest: common.HexToHash("2f74cdeb198af0b9abe65d22d372e22fb2d474371774a9583c1cc427a07939f5"),
- },
- // from proof of concept nine testnet, epoch 1
- {
- number: 30001,
- hashNoNonce: common.HexToHash("7e44356ee3441623bc72a683fd3708fdf75e971bbe294f33e539eedad4b92b34"),
- difficulty: big.NewInt(1532671),
- nonce: 0x318df1c8adef7e5e,
- mixDigest: common.HexToHash("144b180aad09ae3c81fb07be92c8e6351b5646dda80e6844ae1b697e55ddde84"),
- },
- // from proof of concept nine testnet, epoch 2
- {
- number: 60000,
- hashNoNonce: common.HexToHash("5fc898f16035bf5ac9c6d9077ae1e3d5fc1ecc3c9fd5bee8bb00e810fdacbaa0"),
- difficulty: big.NewInt(2467358),
- nonce: 0x50377003e5d830ca,
- mixDigest: common.HexToHash("ab546a5b73c452ae86dadd36f0ed83a6745226717d3798832d1b20b489e82063"),
- },
-}
-
-var invalidZeroDiffBlock = testBlock{
- number: 61440000,
- hashNoNonce: crypto.Sha3Hash([]byte("foo")),
- difficulty: big.NewInt(0),
- nonce: 0xcafebabec00000fe,
- mixDigest: crypto.Sha3Hash([]byte("bar")),
-}
-
-func TestEthashVerifyValid(t *testing.T) {
- eth := New()
- for i, block := range validBlocks {
- if !eth.Verify(block) {
- t.Errorf("block %d (%x) did not validate.", i, block.hashNoNonce[:6])
- }
- }
-}
-
-func TestEthashVerifyInvalid(t *testing.T) {
- eth := New()
- if eth.Verify(&invalidZeroDiffBlock) {
- t.Errorf("should not validate - we just ensure it does not panic on this block")
- }
-}
-
-func TestEthashConcurrentVerify(t *testing.T) {
- eth, err := NewForTesting()
- if err != nil {
- t.Fatal(err)
- }
- defer os.RemoveAll(eth.Full.Dir)
-
- block := &testBlock{difficulty: big.NewInt(10)}
- nonce, md := eth.Search(block, nil, 0)
- block.nonce = nonce
- block.mixDigest = common.BytesToHash(md)
-
- // Verify the block concurrently to check for data races.
- var wg sync.WaitGroup
- wg.Add(100)
- for i := 0; i < 100; i++ {
- go func() {
- if !eth.Verify(block) {
- t.Error("Block could not be verified")
- }
- wg.Done()
- }()
- }
- wg.Wait()
-}
-
-func TestEthashConcurrentSearch(t *testing.T) {
- eth, err := NewForTesting()
- if err != nil {
- t.Fatal(err)
- }
- eth.Turbo(true)
- defer os.RemoveAll(eth.Full.Dir)
-
- type searchRes struct {
- n uint64
- md []byte
- }
-
- var (
- block = &testBlock{difficulty: big.NewInt(35000)}
- nsearch = 10
- wg = new(sync.WaitGroup)
- found = make(chan searchRes)
- stop = make(chan struct{})
- )
- rand.Read(block.hashNoNonce[:])
- wg.Add(nsearch)
- // launch n searches concurrently.
- for i := 0; i < nsearch; i++ {
- go func() {
- nonce, md := eth.Search(block, stop, 0)
- select {
- case found <- searchRes{n: nonce, md: md}:
- case <-stop:
- }
- wg.Done()
- }()
- }
-
- // wait for one of them to find the nonce
- res := <-found
- // stop the others
- close(stop)
- wg.Wait()
-
- block.nonce = res.n
- block.mixDigest = common.BytesToHash(res.md)
- if !eth.Verify(block) {
- t.Error("Block could not be verified")
- }
-}
-
-func TestEthashSearchAcrossEpoch(t *testing.T) {
- eth, err := NewForTesting()
- if err != nil {
- t.Fatal(err)
- }
- defer os.RemoveAll(eth.Full.Dir)
-
- for i := epochLength - 40; i < epochLength+40; i++ {
- block := &testBlock{number: i, difficulty: big.NewInt(90)}
- rand.Read(block.hashNoNonce[:])
- nonce, md := eth.Search(block, nil, 0)
- block.nonce = nonce
- block.mixDigest = common.BytesToHash(md)
- if !eth.Verify(block) {
- t.Fatalf("Block could not be verified")
- }
- }
-}
-
-func TestGetSeedHash(t *testing.T) {
- seed0, err := GetSeedHash(0)
- if err != nil {
- t.Errorf("Failed to get seedHash for block 0: %v", err)
- }
- if bytes.Compare(seed0, make([]byte, 32)) != 0 {
- log.Printf("seedHash for block 0 should be 0s, was: %v\n", seed0)
- }
- seed1, err := GetSeedHash(30000)
- if err != nil {
- t.Error(err)
- }
-
- // From python:
- // > from pyethash import get_seedhash
- // > get_seedhash(30000)
- expectedSeed1, err := hex.DecodeString("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563")
- if err != nil {
- t.Error(err)
- }
-
- if bytes.Compare(seed1, expectedSeed1) != 0 {
- log.Printf("seedHash for block 1 should be: %v,\nactual value: %v\n", expectedSeed1, seed1)
- }
-
-}
diff --git a/Godeps/_workspace/src/github.com/fatih/color/color.go b/Godeps/_workspace/src/github.com/fatih/color/color.go
index c4a10c3c8..e3e997284 100644
--- a/Godeps/_workspace/src/github.com/fatih/color/color.go
+++ b/Godeps/_workspace/src/github.com/fatih/color/color.go
@@ -6,8 +6,8 @@ import (
"strconv"
"strings"
+ "github.com/mattn/go-colorable"
"github.com/mattn/go-isatty"
- "github.com/shiena/ansicolor"
)
// NoColor defines if the output is colorized or not. It's dynamically set to
@@ -53,6 +53,18 @@ const (
FgWhite
)
+// Foreground Hi-Intensity text colors
+const (
+ FgHiBlack Attribute = iota + 90
+ FgHiRed
+ FgHiGreen
+ FgHiYellow
+ FgHiBlue
+ FgHiMagenta
+ FgHiCyan
+ FgHiWhite
+)
+
// Background text colors
const (
BgBlack Attribute = iota + 40
@@ -65,6 +77,18 @@ const (
BgWhite
)
+// Background Hi-Intensity text colors
+const (
+ BgHiBlack Attribute = iota + 100
+ BgHiRed
+ BgHiGreen
+ BgHiYellow
+ BgHiBlue
+ BgHiMagenta
+ BgHiCyan
+ BgHiWhite
+)
+
// New returns a newly created color object.
func New(value ...Attribute) *Color {
c := &Color{params: make([]Attribute, 0)}
@@ -123,7 +147,7 @@ func (c *Color) prepend(value Attribute) {
// Output defines the standard output of the print functions. By default
// os.Stdout is used.
-var Output = ansicolor.NewAnsiColorWriter(os.Stdout)
+var Output = colorable.NewColorableStdout()
// Print formats using the default formats for its operands and writes to
// standard output. Spaces are added between operands when neither is a
@@ -259,6 +283,31 @@ func (c *Color) isNoColorSet() bool {
return NoColor
}
+// Equals returns a boolean value indicating whether two colors are equal.
+func (c *Color) Equals(c2 *Color) bool {
+ if len(c.params) != len(c2.params) {
+ return false
+ }
+
+ for _, attr := range c.params {
+ if !c2.attrExists(attr) {
+ return false
+ }
+ }
+
+ return true
+}
+
+func (c *Color) attrExists(a Attribute) bool {
+ for _, attr := range c.params {
+ if attr == a {
+ return true
+ }
+ }
+
+ return false
+}
+
func boolPtr(v bool) *bool {
return &v
}
diff --git a/Godeps/_workspace/src/github.com/fatih/color/color_test.go b/Godeps/_workspace/src/github.com/fatih/color/color_test.go
deleted file mode 100644
index a1192b559..000000000
--- a/Godeps/_workspace/src/github.com/fatih/color/color_test.go
+++ /dev/null
@@ -1,176 +0,0 @@
-package color
-
-import (
- "bytes"
- "fmt"
- "os"
- "testing"
-
- "github.com/shiena/ansicolor"
-)
-
-// Testing colors is kinda different. First we test for given colors and their
-// escaped formatted results. Next we create some visual tests to be tested.
-// Each visual test includes the color name to be compared.
-func TestColor(t *testing.T) {
- rb := new(bytes.Buffer)
- Output = rb
-
- testColors := []struct {
- text string
- code Attribute
- }{
- {text: "black", code: FgBlack},
- {text: "red", code: FgRed},
- {text: "green", code: FgGreen},
- {text: "yellow", code: FgYellow},
- {text: "blue", code: FgBlue},
- {text: "magent", code: FgMagenta},
- {text: "cyan", code: FgCyan},
- {text: "white", code: FgWhite},
- }
-
- for _, c := range testColors {
- New(c.code).Print(c.text)
-
- line, _ := rb.ReadString('\n')
- scannedLine := fmt.Sprintf("%q", line)
- colored := fmt.Sprintf("\x1b[%dm%s\x1b[0m", c.code, c.text)
- escapedForm := fmt.Sprintf("%q", colored)
-
- fmt.Printf("%s\t: %s\n", c.text, line)
-
- if scannedLine != escapedForm {
- t.Errorf("Expecting %s, got '%s'\n", escapedForm, scannedLine)
- }
- }
-}
-
-func TestNoColor(t *testing.T) {
- rb := new(bytes.Buffer)
- Output = rb
-
- testColors := []struct {
- text string
- code Attribute
- }{
- {text: "black", code: FgBlack},
- {text: "red", code: FgRed},
- {text: "green", code: FgGreen},
- {text: "yellow", code: FgYellow},
- {text: "blue", code: FgBlue},
- {text: "magent", code: FgMagenta},
- {text: "cyan", code: FgCyan},
- {text: "white", code: FgWhite},
- }
-
- for _, c := range testColors {
- p := New(c.code)
- p.DisableColor()
- p.Print(c.text)
-
- line, _ := rb.ReadString('\n')
- if line != c.text {
- t.Errorf("Expecting %s, got '%s'\n", c.text, line)
- }
- }
-
- // global check
- NoColor = true
- defer func() {
- NoColor = false
- }()
- for _, c := range testColors {
- p := New(c.code)
- p.Print(c.text)
-
- line, _ := rb.ReadString('\n')
- if line != c.text {
- t.Errorf("Expecting %s, got '%s'\n", c.text, line)
- }
- }
-
-}
-
-func TestColorVisual(t *testing.T) {
- // First Visual Test
- fmt.Println("")
- Output = ansicolor.NewAnsiColorWriter(os.Stdout)
-
- New(FgRed).Printf("red\t")
- New(BgRed).Print(" ")
- New(FgRed, Bold).Println(" red")
-
- New(FgGreen).Printf("green\t")
- New(BgGreen).Print(" ")
- New(FgGreen, Bold).Println(" green")
-
- New(FgYellow).Printf("yellow\t")
- New(BgYellow).Print(" ")
- New(FgYellow, Bold).Println(" yellow")
-
- New(FgBlue).Printf("blue\t")
- New(BgBlue).Print(" ")
- New(FgBlue, Bold).Println(" blue")
-
- New(FgMagenta).Printf("magenta\t")
- New(BgMagenta).Print(" ")
- New(FgMagenta, Bold).Println(" magenta")
-
- New(FgCyan).Printf("cyan\t")
- New(BgCyan).Print(" ")
- New(FgCyan, Bold).Println(" cyan")
-
- New(FgWhite).Printf("white\t")
- New(BgWhite).Print(" ")
- New(FgWhite, Bold).Println(" white")
- fmt.Println("")
-
- // Second Visual test
- Black("black")
- Red("red")
- Green("green")
- Yellow("yellow")
- Blue("blue")
- Magenta("magenta")
- Cyan("cyan")
- White("white")
-
- // Third visual test
- fmt.Println()
- Set(FgBlue)
- fmt.Println("is this blue?")
- Unset()
-
- Set(FgMagenta)
- fmt.Println("and this magenta?")
- Unset()
-
- // Fourth Visual test
- fmt.Println()
- blue := New(FgBlue).PrintlnFunc()
- blue("blue text with custom print func")
-
- red := New(FgRed).PrintfFunc()
- red("red text with a printf func: %d\n", 123)
-
- put := New(FgYellow).SprintFunc()
- warn := New(FgRed).SprintFunc()
-
- fmt.Fprintf(Output, "this is a %s and this is %s.\n", put("warning"), warn("error"))
-
- info := New(FgWhite, BgGreen).SprintFunc()
- fmt.Fprintf(Output, "this %s rocks!\n", info("package"))
-
- // Fifth Visual Test
- fmt.Println()
-
- fmt.Fprintln(Output, BlackString("black"))
- fmt.Fprintln(Output, RedString("red"))
- fmt.Fprintln(Output, GreenString("green"))
- fmt.Fprintln(Output, YellowString("yellow"))
- fmt.Fprintln(Output, BlueString("blue"))
- fmt.Fprintln(Output, MagentaString("magenta"))
- fmt.Fprintln(Output, CyanString("cyan"))
- fmt.Fprintln(Output, WhiteString("white"))
-}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/.gitignore b/Godeps/_workspace/src/github.com/gizak/termui/.gitignore
index daf913b1b..eb1369fd4 100644
--- a/Godeps/_workspace/src/github.com/gizak/termui/.gitignore
+++ b/Godeps/_workspace/src/github.com/gizak/termui/.gitignore
@@ -22,3 +22,4 @@ _testmain.go
*.exe
*.test
*.prof
+.DS_Store
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/README.md b/Godeps/_workspace/src/github.com/gizak/termui/README.md
index b9bc3024d..0e1d41b08 100644
--- a/Godeps/_workspace/src/github.com/gizak/termui/README.md
+++ b/Godeps/_workspace/src/github.com/gizak/termui/README.md
@@ -1,55 +1,30 @@
# termui [![Build Status](https://travis-ci.org/gizak/termui.svg?branch=master)](https://travis-ci.org/gizak/termui) [![Doc Status](https://godoc.org/github.com/gizak/termui?status.png)](https://godoc.org/github.com/gizak/termui)
-## Update 23/06/2015
-Pull requests and master branch are freezing, waiting for merging from `refactoring` branch.
+<img src="./_example/dashboard.gif" alt="demo cast under osx 10.10; Terminal.app; Menlo Regular 12pt.)" width="80%">
-## Notice
-termui comes with ABSOLUTELY NO WARRANTY, and there is a breaking change coming up (see refactoring branch) which will change the `Bufferer` interface and many others. These changes reduce calculation overhead and introduce a new drawing buffer with better capacibilities. We will step into the next stage (call it beta) after merging these changes.
+`termui` is a cross-platform, easy-to-compile, and fully-customizable terminal dashboard. It is inspired by [blessed-contrib](https://github.com/yaronn/blessed-contrib), but purely in Go.
-## Introduction
-Go terminal dashboard. Inspired by [blessed-contrib](https://github.com/yaronn/blessed-contrib), but purely in Go.
+Now version v2 has arrived! It brings new event system, new theme system, new `Buffer` interface and specific colour text rendering. (some docs are missing, but it will be completed soon!)
-Cross-platform, easy to compile, and fully-customizable.
-
-__Demo:__ (cast under osx 10.10; Terminal.app; Menlo Regular 12pt.)
+## Installation
-<img src="./example/dashboard.gif" alt="demo" width="600">
+`master` mirrors v2 branch, to install:
-__Grid layout:__
+ go get -u github.com/gizak/termui
-Expressive syntax, using [12 columns grid system](http://www.w3schools.com/bootstrap/bootstrap_grid_system.asp)
-```go
- import ui "github.com/gizak/termui"
- // init and create widgets...
+For the compatible reason, you can choose to install the legacy version of `termui`:
- // build
- ui.Body.AddRows(
- ui.NewRow(
- ui.NewCol(6, 0, widget0),
- ui.NewCol(6, 0, widget1)),
- ui.NewRow(
- ui.NewCol(3, 0, widget2),
- ui.NewCol(3, 0, widget30, widget31, widget32),
- ui.NewCol(6, 0, widget4)))
+ go get gopkg.in/gizak/termui.v1
- // calculate layout
- ui.Body.Align()
-
- ui.Render(ui.Body)
-```
-[demo code:](https://github.com/gizak/termui/blob/master/example/grid.go)
-
-<img src="./example/grid.gif" alt="grid" width="500">
-
-## Installation
+## Usage
- go get github.com/gizak/termui
+### Layout
-## Usage
+To use `termui`, the very first thing you may want to know is how to manage layout. `termui` offers two ways of doing this, known as absolute layout and grid layout.
-Each component's layout is a bit like HTML block (box model), which has border and padding.
+__Absolute layout__
-The `Border` property can be chosen to hide or display (with its border label), when it comes to display, the label takes 1 padding space (i.e. in css: `padding: 1;`, innerHeight and innerWidth therefore shrunk by 1).
+Each widget has an underlying block structure which basically is a box model. It has border, label and padding properties. A border of a widget can be chosen to hide or display (with its border label), you can pick a different front/back colour for the border as well. To display such a widget at a specific location in terminal window, you need to assign `.X`, `.Y`, `.Height`, `.Width` values for each widget before send it to `.Render`. Let's demonstrate these by a code snippet:
`````go
import ui "github.com/gizak/termui" // <- ui shortcut, optional
@@ -65,20 +40,20 @@ The `Border` property can be chosen to hide or display (with its border label),
p.Height = 3
p.Width = 50
p.TextFgColor = ui.ColorWhite
- p.Border.Label = "Text Box"
- p.Border.FgColor = ui.ColorCyan
+ p.BorderLabel = "Text Box"
+ p.BorderFg = ui.ColorCyan
g := ui.NewGauge()
g.Percent = 50
g.Width = 50
g.Height = 3
g.Y = 11
- g.Border.Label = "Gauge"
+ g.BorderLabel = "Gauge"
g.BarColor = ui.ColorRed
- g.Border.FgColor = ui.ColorWhite
- g.Border.LabelFgColor = ui.ColorCyan
+ g.BorderFg = ui.ColorWhite
+ g.BorderLabelFg = ui.ColorCyan
- ui.Render(p, g)
+ ui.Render(p, g) // feel free to call Render, it's async and non-block
// event handler...
}
@@ -86,62 +61,74 @@ The `Border` property can be chosen to hide or display (with its border label),
Note that components can be overlapped (I'd rather call this a feature...), `Render(rs ...Renderer)` renders its args from left to right (i.e. each component's weight is arising from left to right).
-## Themes
-
-_All_ colors in _all_ components can be changed at _any_ time, while there provides some predefined color schemes:
-
-```go
-// for now there are only two themes: default and helloworld
-termui.UseTheme("helloworld")
-
-// create components...
-```
-The `default ` theme's settings depend on the user's terminal color scheme, which is saying if your terminal default font color is white and background is white, it will be like:
-
-<img src="./example/themedefault.png" alt="default" type="image/png" width="600">
-
-The `helloworld` color scheme drops in some colors!
-
-<img src="./example/themehelloworld.png" alt="helloworld" type="image/png" width="600">
-
-## Widgets
-
-#### Par
-
-[demo code](https://github.com/gizak/termui/blob/master/example/par.go)
-
-<img src="./example/par.png" alt="par" type="image/png" width="300">
+__Grid layout:__
-#### List
-[demo code](https://github.com/gizak/termui/blob/master/example/list.go)
+<img src="./_example/grid.gif" alt="grid" width="60%">
-<img src="./example/list.png" alt="list" type="image/png" width="200">
+Grid layout uses [12 columns grid system](http://www.w3schools.com/bootstrap/bootstrap_grid_system.asp) with expressive syntax. To use `Grid`, all we need to do is build a widget tree consisting of `Row`s and Cols (Actually a Col is also a `Row` but with a widget endpoint attached).
-#### Gauge
-[demo code](https://github.com/gizak/termui/blob/master/example/gauge.go)
+```go
+ import ui "github.com/gizak/termui"
+ // init and create widgets...
-<img src="./example/gauge.png" alt="gauge" type="image/png" width="350">
+ // build
+ ui.Body.AddRows(
+ ui.NewRow(
+ ui.NewCol(6, 0, widget0),
+ ui.NewCol(6, 0, widget1)),
+ ui.NewRow(
+ ui.NewCol(3, 0, widget2),
+ ui.NewCol(3, 0, widget30, widget31, widget32),
+ ui.NewCol(6, 0, widget4)))
-#### Line Chart
-[demo code](https://github.com/gizak/termui/blob/master/example/linechart.go)
+ // calculate layout
+ ui.Body.Align()
-<img src="./example/linechart.png" alt="linechart" type="image/png" width="450">
+ ui.Render(ui.Body)
+```
-#### Bar Chart
-[demo code](https://github.com/gizak/termui/blob/master/example/barchart.go)
+### Events
-<img src="./example/barchart.png" alt="barchart" type="image/png" width="150">
+`termui` ships with a http-like event mux handling system. All events are channeled up from different sources (typing, click, windows resize, custom event) and then encoded as universal `Event` object. `Event.Path` indicates the event type and `Event.Data` stores the event data struct. Add a handler to a certain event is easy as below:
-#### Mult-Bar / Stacked-Bar Chart
-[demo code](https://github.com/gizak/termui/blob/master/example/mbarchart.go)
+```go
+ // handle key q pressing
+ ui.Handle("/sys/kbd/q", func(ui.Event) {
+ // press q to quit
+ ui.StopLoop()
+ })
+
+ ui.Handle("/sys/kbd/C-x", func(ui.Event) {
+ // handle Ctrl + x combination
+ })
+
+ ui.Handle("/sys/kbd", func(ui.Event) {
+ // handle all other key pressing
+ })
+
+ // handle a 1s timer
+ ui.Handle("/timer/1s", func(e ui.Event) {
+ t := e.Data.(ui.EvtTimer)
+ // t is a EvtTimer
+ if t.Count%2 ==0 {
+ // do something
+ }
+ })
-<img src="./example/mbarchart.png" alt="barchart" type="image/png" width="150">
+ ui.Loop() // block until StopLoop is called
+```
-#### Sparklines
-[demo code](https://github.com/gizak/termui/blob/master/example/sparklines.go)
+### Widgets
-<img src="./example/sparklines.png" alt="sparklines" type="image/png" width="350">
+Click image to see the corresponding demo codes.
+[<img src="./_example/par.png" alt="par" type="image/png" width="45%">](https://github.com/gizak/termui/blob/master/_example/par.go)
+[<img src="./_example/list.png" alt="list" type="image/png" width="45%">](https://github.com/gizak/termui/blob/master/_example/list.go)
+[<img src="./_example/gauge.png" alt="gauge" type="image/png" width="45%">](https://github.com/gizak/termui/blob/master/_example/gauge.go)
+[<img src="./_example/linechart.png" alt="linechart" type="image/png" width="45%">](https://github.com/gizak/termui/blob/master/_example/linechart.go)
+[<img src="./_example/barchart.png" alt="barchart" type="image/png" width="45%">](https://github.com/gizak/termui/blob/master/_example/barchart.go)
+[<img src="./_example/mbarchart.png" alt="barchart" type="image/png" width="45%">](https://github.com/gizak/termui/blob/master/_example/mbarchart.go)
+[<img src="./_example/sparklines.png" alt="sparklines" type="image/png" width="45%">](https://github.com/gizak/termui/blob/master/_example/sparklines.go)
## GoDoc
@@ -150,10 +137,12 @@ The `helloworld` color scheme drops in some colors!
## TODO
- [x] Grid layout
-- [ ] Event system
-- [ ] Canvas widget
-- [ ] Refine APIs
+- [x] Event system
+- [x] Canvas widget
+- [x] Refine APIs
- [ ] Focusable widgets
+## Changelog
+
## License
This library is under the [MIT License](http://opensource.org/licenses/MIT)
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/bar.go b/Godeps/_workspace/src/github.com/gizak/termui/barchart.go
index 57bae0ae8..980e958e2 100644
--- a/Godeps/_workspace/src/github.com/gizak/termui/bar.go
+++ b/Godeps/_workspace/src/github.com/gizak/termui/barchart.go
@@ -1,4 +1,4 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
+// Copyright 2016 Zack Guo <gizak@icloud.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
@@ -39,16 +39,16 @@ type BarChart struct {
// NewBarChart returns a new *BarChart with current theme.
func NewBarChart() *BarChart {
bc := &BarChart{Block: *NewBlock()}
- bc.BarColor = theme.BarChartBar
- bc.NumColor = theme.BarChartNum
- bc.TextColor = theme.BarChartText
+ bc.BarColor = ThemeAttr("barchart.bar.bg")
+ bc.NumColor = ThemeAttr("barchart.num.fg")
+ bc.TextColor = ThemeAttr("barchart.text.fg")
bc.BarGap = 1
bc.BarWidth = 3
return bc
}
func (bc *BarChart) layout() {
- bc.numBar = bc.innerWidth / (bc.BarGap + bc.BarWidth)
+ bc.numBar = bc.innerArea.Dx() / (bc.BarGap + bc.BarWidth)
bc.labels = make([][]rune, bc.numBar)
bc.dataNum = make([][]rune, len(bc.Data))
@@ -69,7 +69,7 @@ func (bc *BarChart) layout() {
bc.max = bc.Data[i]
}
}
- bc.scale = float64(bc.max) / float64(bc.innerHeight-1)
+ bc.scale = float64(bc.max) / float64(bc.innerArea.Dy()-1)
}
func (bc *BarChart) SetMax(max int) {
@@ -80,8 +80,8 @@ func (bc *BarChart) SetMax(max int) {
}
// Buffer implements Bufferer interface.
-func (bc *BarChart) Buffer() []Point {
- ps := bc.Block.Buffer()
+func (bc *BarChart) Buffer() Buffer {
+ buf := bc.Block.Buffer()
bc.layout()
for i := 0; i < bc.numBar && i < len(bc.Data) && i < len(bc.DataLabels); i++ {
@@ -90,46 +90,49 @@ func (bc *BarChart) Buffer() []Point {
// plot bar
for j := 0; j < bc.BarWidth; j++ {
for k := 0; k < h; k++ {
- p := Point{}
- p.Ch = ' '
- p.Bg = bc.BarColor
+ c := Cell{
+ Ch: ' ',
+ Bg: bc.BarColor,
+ }
if bc.BarColor == ColorDefault { // when color is default, space char treated as transparent!
- p.Bg |= AttrReverse
+ c.Bg |= AttrReverse
}
- p.X = bc.innerX + i*(bc.BarWidth+bc.BarGap) + j
- p.Y = bc.innerY + bc.innerHeight - 2 - k
- ps = append(ps, p)
+ x := bc.innerArea.Min.X + i*(bc.BarWidth+bc.BarGap) + j
+ y := bc.innerArea.Min.Y + bc.innerArea.Dy() - 2 - k
+ buf.Set(x, y, c)
}
}
// plot text
for j, k := 0, 0; j < len(bc.labels[i]); j++ {
w := charWidth(bc.labels[i][j])
- p := Point{}
- p.Ch = bc.labels[i][j]
- p.Bg = bc.BgColor
- p.Fg = bc.TextColor
- p.Y = bc.innerY + bc.innerHeight - 1
- p.X = bc.innerX + oftX + k
- ps = append(ps, p)
+ c := Cell{
+ Ch: bc.labels[i][j],
+ Bg: bc.Bg,
+ Fg: bc.TextColor,
+ }
+ y := bc.innerArea.Min.Y + bc.innerArea.Dy() - 1
+ x := bc.innerArea.Min.X + oftX + k
+ buf.Set(x, y, c)
k += w
}
// plot num
for j := 0; j < len(bc.dataNum[i]); j++ {
- p := Point{}
- p.Ch = bc.dataNum[i][j]
- p.Fg = bc.NumColor
- p.Bg = bc.BarColor
+ c := Cell{
+ Ch: bc.dataNum[i][j],
+ Fg: bc.NumColor,
+ Bg: bc.BarColor,
+ }
if bc.BarColor == ColorDefault { // the same as above
- p.Bg |= AttrReverse
+ c.Bg |= AttrReverse
}
if h == 0 {
- p.Bg = bc.BgColor
+ c.Bg = bc.Bg
}
- p.X = bc.innerX + oftX + (bc.BarWidth-len(bc.dataNum[i]))/2 + j
- p.Y = bc.innerY + bc.innerHeight - 2
- ps = append(ps, p)
+ x := bc.innerArea.Min.X + oftX + (bc.BarWidth-len(bc.dataNum[i]))/2 + j
+ y := bc.innerArea.Min.Y + bc.innerArea.Dy() - 2
+ buf.Set(x, y, c)
}
}
- return bc.Block.chopOverflow(ps)
+ return buf
}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/block.go b/Godeps/_workspace/src/github.com/gizak/termui/block.go
index 953136596..418738c8d 100644
--- a/Godeps/_workspace/src/github.com/gizak/termui/block.go
+++ b/Godeps/_workspace/src/github.com/gizak/termui/block.go
@@ -1,142 +1,240 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
+// Copyright 2016 Zack Guo <gizak@icloud.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
package termui
+import "image"
+
+// Hline is a horizontal line.
+type Hline struct {
+ X int
+ Y int
+ Len int
+ Fg Attribute
+ Bg Attribute
+}
+
+// Vline is a vertical line.
+type Vline struct {
+ X int
+ Y int
+ Len int
+ Fg Attribute
+ Bg Attribute
+}
+
+// Buffer draws a horizontal line.
+func (l Hline) Buffer() Buffer {
+ if l.Len <= 0 {
+ return NewBuffer()
+ }
+ return NewFilledBuffer(l.X, l.Y, l.X+l.Len, l.Y+1, HORIZONTAL_LINE, l.Fg, l.Bg)
+}
+
+// Buffer draws a vertical line.
+func (l Vline) Buffer() Buffer {
+ if l.Len <= 0 {
+ return NewBuffer()
+ }
+ return NewFilledBuffer(l.X, l.Y, l.X+1, l.Y+l.Len, VERTICAL_LINE, l.Fg, l.Bg)
+}
+
+// Buffer draws a box border.
+func (b Block) drawBorder(buf Buffer) {
+ if !b.Border {
+ return
+ }
+
+ min := b.area.Min
+ max := b.area.Max
+
+ x0 := min.X
+ y0 := min.Y
+ x1 := max.X - 1
+ y1 := max.Y - 1
+
+ // draw lines
+ if b.BorderTop {
+ buf.Merge(Hline{x0, y0, x1 - x0, b.BorderFg, b.BorderBg}.Buffer())
+ }
+ if b.BorderBottom {
+ buf.Merge(Hline{x0, y1, x1 - x0, b.BorderFg, b.BorderBg}.Buffer())
+ }
+ if b.BorderLeft {
+ buf.Merge(Vline{x0, y0, y1 - y0, b.BorderFg, b.BorderBg}.Buffer())
+ }
+ if b.BorderRight {
+ buf.Merge(Vline{x1, y0, y1 - y0, b.BorderFg, b.BorderBg}.Buffer())
+ }
+
+ // draw corners
+ if b.BorderTop && b.BorderLeft && b.area.Dx() > 0 && b.area.Dy() > 0 {
+ buf.Set(x0, y0, Cell{TOP_LEFT, b.BorderFg, b.BorderBg})
+ }
+ if b.BorderTop && b.BorderRight && b.area.Dx() > 1 && b.area.Dy() > 0 {
+ buf.Set(x1, y0, Cell{TOP_RIGHT, b.BorderFg, b.BorderBg})
+ }
+ if b.BorderBottom && b.BorderLeft && b.area.Dx() > 0 && b.area.Dy() > 1 {
+ buf.Set(x0, y1, Cell{BOTTOM_LEFT, b.BorderFg, b.BorderBg})
+ }
+ if b.BorderBottom && b.BorderRight && b.area.Dx() > 1 && b.area.Dy() > 1 {
+ buf.Set(x1, y1, Cell{BOTTOM_RIGHT, b.BorderFg, b.BorderBg})
+ }
+}
+
+func (b Block) drawBorderLabel(buf Buffer) {
+ maxTxtW := b.area.Dx() - 2
+ tx := DTrimTxCls(DefaultTxBuilder.Build(b.BorderLabel, b.BorderLabelFg, b.BorderLabelBg), maxTxtW)
+
+ for i, w := 0, 0; i < len(tx); i++ {
+ buf.Set(b.area.Min.X+1+w, b.area.Min.Y, tx[i])
+ w += tx[i].Width()
+ }
+}
+
// Block is a base struct for all other upper level widgets,
// consider it as css: display:block.
// Normally you do not need to create it manually.
type Block struct {
+ area image.Rectangle
+ innerArea image.Rectangle
X int
Y int
- Border labeledBorder
- IsDisplay bool
- HasBorder bool
- BgColor Attribute
+ Border bool
+ BorderFg Attribute
+ BorderBg Attribute
+ BorderLeft bool
+ BorderRight bool
+ BorderTop bool
+ BorderBottom bool
+ BorderLabel string
+ BorderLabelFg Attribute
+ BorderLabelBg Attribute
+ Display bool
+ Bg Attribute
Width int
Height int
- innerWidth int
- innerHeight int
- innerX int
- innerY int
PaddingTop int
PaddingBottom int
PaddingLeft int
PaddingRight int
+ id string
+ Float Align
}
// NewBlock returns a *Block which inherits styles from current theme.
func NewBlock() *Block {
- d := Block{}
- d.IsDisplay = true
- d.HasBorder = theme.HasBorder
- d.Border.BgColor = theme.BorderBg
- d.Border.FgColor = theme.BorderFg
- d.Border.LabelBgColor = theme.BorderLabelTextBg
- d.Border.LabelFgColor = theme.BorderLabelTextFg
- d.BgColor = theme.BlockBg
- d.Width = 2
- d.Height = 2
- return &d
-}
-
-// compute box model
-func (d *Block) align() {
- d.innerWidth = d.Width - d.PaddingLeft - d.PaddingRight
- d.innerHeight = d.Height - d.PaddingTop - d.PaddingBottom
- d.innerX = d.X + d.PaddingLeft
- d.innerY = d.Y + d.PaddingTop
-
- if d.HasBorder {
- d.innerHeight -= 2
- d.innerWidth -= 2
- d.Border.X = d.X
- d.Border.Y = d.Y
- d.Border.Width = d.Width
- d.Border.Height = d.Height
- d.innerX++
- d.innerY++
- }
+ b := Block{}
+ b.Display = true
+ b.Border = true
+ b.BorderLeft = true
+ b.BorderRight = true
+ b.BorderTop = true
+ b.BorderBottom = true
+ b.BorderBg = ThemeAttr("border.bg")
+ b.BorderFg = ThemeAttr("border.fg")
+ b.BorderLabelBg = ThemeAttr("label.bg")
+ b.BorderLabelFg = ThemeAttr("label.fg")
+ b.Bg = ThemeAttr("block.bg")
+ b.Width = 2
+ b.Height = 2
+ b.id = GenId()
+ b.Float = AlignNone
+ return &b
+}
- if d.innerHeight < 0 {
- d.innerHeight = 0
- }
- if d.innerWidth < 0 {
- d.innerWidth = 0
- }
+func (b Block) Id() string {
+ return b.id
+}
+// Align computes box model
+func (b *Block) Align() {
+ // outer
+ b.area.Min.X = 0
+ b.area.Min.Y = 0
+ b.area.Max.X = b.Width
+ b.area.Max.Y = b.Height
+
+ // float
+ b.area = AlignArea(TermRect(), b.area, b.Float)
+ b.area = MoveArea(b.area, b.X, b.Y)
+
+ // inner
+ b.innerArea.Min.X = b.area.Min.X + b.PaddingLeft
+ b.innerArea.Min.Y = b.area.Min.Y + b.PaddingTop
+ b.innerArea.Max.X = b.area.Max.X - b.PaddingRight
+ b.innerArea.Max.Y = b.area.Max.Y - b.PaddingBottom
+
+ if b.Border {
+ if b.BorderLeft {
+ b.innerArea.Min.X++
+ }
+ if b.BorderRight {
+ b.innerArea.Max.X--
+ }
+ if b.BorderTop {
+ b.innerArea.Min.Y++
+ }
+ if b.BorderBottom {
+ b.innerArea.Max.Y--
+ }
+ }
}
// InnerBounds returns the internal bounds of the block after aligning and
// calculating the padding and border, if any.
-func (d *Block) InnerBounds() (x, y, width, height int) {
- d.align()
- return d.innerX, d.innerY, d.innerWidth, d.innerHeight
+func (b *Block) InnerBounds() image.Rectangle {
+ b.Align()
+ return b.innerArea
}
// Buffer implements Bufferer interface.
// Draw background and border (if any).
-func (d *Block) Buffer() []Point {
- d.align()
+func (b *Block) Buffer() Buffer {
+ b.Align()
- ps := []Point{}
- if !d.IsDisplay {
- return ps
- }
+ buf := NewBuffer()
+ buf.SetArea(b.area)
+ buf.Fill(' ', ColorDefault, b.Bg)
- if d.HasBorder {
- ps = d.Border.Buffer()
- }
+ b.drawBorder(buf)
+ b.drawBorderLabel(buf)
- for i := 0; i < d.innerWidth; i++ {
- for j := 0; j < d.innerHeight; j++ {
- p := Point{}
- p.X = d.X + 1 + i
- p.Y = d.Y + 1 + j
- p.Ch = ' '
- p.Bg = d.BgColor
- ps = append(ps, p)
- }
- }
- return ps
+ return buf
}
// GetHeight implements GridBufferer.
// It returns current height of the block.
-func (d Block) GetHeight() int {
- return d.Height
+func (b Block) GetHeight() int {
+ return b.Height
}
// SetX implements GridBufferer interface, which sets block's x position.
-func (d *Block) SetX(x int) {
- d.X = x
+func (b *Block) SetX(x int) {
+ b.X = x
}
// SetY implements GridBufferer interface, it sets y position for block.
-func (d *Block) SetY(y int) {
- d.Y = y
+func (b *Block) SetY(y int) {
+ b.Y = y
}
// SetWidth implements GridBuffer interface, it sets block's width.
-func (d *Block) SetWidth(w int) {
- d.Width = w
-}
-
-// chop the overflow parts
-func (d *Block) chopOverflow(ps []Point) []Point {
- nps := make([]Point, 0, len(ps))
- x := d.X
- y := d.Y
- w := d.Width
- h := d.Height
- for _, v := range ps {
- if v.X >= x &&
- v.X < x+w &&
- v.Y >= y &&
- v.Y < y+h {
- nps = append(nps, v)
- }
- }
- return nps
+func (b *Block) SetWidth(w int) {
+ b.Width = w
}
+
+func (b Block) InnerWidth() int {
+ return b.innerArea.Dx()
+}
+
+func (b Block) InnerHeight() int {
+ return b.innerArea.Dy()
+}
+
+func (b Block) InnerX() int {
+ return b.innerArea.Min.X
+}
+
+func (b Block) InnerY() int { return b.innerArea.Min.Y }
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/box_others.go b/Godeps/_workspace/src/github.com/gizak/termui/block_common.go
index bcc3d7ded..0f972cbbd 100644
--- a/Godeps/_workspace/src/github.com/gizak/termui/box_others.go
+++ b/Godeps/_workspace/src/github.com/gizak/termui/block_common.go
@@ -1,4 +1,4 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
+// Copyright 2016 Zack Guo <gizak@icloud.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
@@ -12,3 +12,9 @@ const HORIZONTAL_LINE = '─'
const TOP_LEFT = '┌'
const BOTTOM_RIGHT = '┘'
const BOTTOM_LEFT = '└'
+const VERTICAL_LEFT = '┤'
+const VERTICAL_RIGHT = '├'
+const HORIZONTAL_DOWN = '┬'
+const HORIZONTAL_UP = '┴'
+const QUOTA_LEFT = '«'
+const QUOTA_RIGHT = '»'
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/block_test.go b/Godeps/_workspace/src/github.com/gizak/termui/block_test.go
deleted file mode 100644
index 2de205b21..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/block_test.go
+++ /dev/null
@@ -1,46 +0,0 @@
-package termui
-
-import "testing"
-
-func TestBlock_InnerBounds(t *testing.T) {
- b := NewBlock()
- b.X = 10
- b.Y = 11
- b.Width = 12
- b.Height = 13
-
- assert := func(name string, x, y, w, h int) {
- t.Log(name)
- cx, cy, cw, ch := b.InnerBounds()
- if cx != x {
- t.Errorf("expected x to be %d but got %d", x, cx)
- }
- if cy != y {
- t.Errorf("expected y to be %d but got %d", y, cy)
- }
- if cw != w {
- t.Errorf("expected width to be %d but got %d", w, cw)
- }
- if ch != h {
- t.Errorf("expected height to be %d but got %d", h, ch)
- }
- }
-
- b.HasBorder = false
- assert("no border, no padding", 10, 11, 12, 13)
-
- b.HasBorder = true
- assert("border, no padding", 11, 12, 10, 11)
-
- b.PaddingBottom = 2
- assert("border, 2b padding", 11, 12, 10, 9)
-
- b.PaddingTop = 3
- assert("border, 2b 3t padding", 11, 15, 10, 6)
-
- b.PaddingLeft = 4
- assert("border, 2b 3t 4l padding", 15, 15, 6, 6)
-
- b.PaddingRight = 5
- assert("border, 2b 3t 4l 5r padding", 15, 15, 1, 6)
-}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/box_windows.go b/Godeps/_workspace/src/github.com/gizak/termui/block_windows.go
index dd39019fe..4dbc017de 100644
--- a/Godeps/_workspace/src/github.com/gizak/termui/box_windows.go
+++ b/Godeps/_workspace/src/github.com/gizak/termui/block_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
+// Copyright 2016 Zack Guo <gizak@icloud.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/box.go b/Godeps/_workspace/src/github.com/gizak/termui/box.go
deleted file mode 100644
index 1dcfd8692..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/box.go
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
-// Use of this source code is governed by a MIT license that can
-// be found in the LICENSE file.
-
-package termui
-
-type border struct {
- X int
- Y int
- Width int
- Height int
- FgColor Attribute
- BgColor Attribute
-}
-
-type hline struct {
- X int
- Y int
- Length int
- FgColor Attribute
- BgColor Attribute
-}
-
-type vline struct {
- X int
- Y int
- Length int
- FgColor Attribute
- BgColor Attribute
-}
-
-// Draw a horizontal line.
-func (l hline) Buffer() []Point {
- pts := make([]Point, l.Length)
- for i := 0; i < l.Length; i++ {
- pts[i].X = l.X + i
- pts[i].Y = l.Y
- pts[i].Ch = HORIZONTAL_LINE
- pts[i].Bg = l.BgColor
- pts[i].Fg = l.FgColor
- }
- return pts
-}
-
-// Draw a vertical line.
-func (l vline) Buffer() []Point {
- pts := make([]Point, l.Length)
- for i := 0; i < l.Length; i++ {
- pts[i].X = l.X
- pts[i].Y = l.Y + i
- pts[i].Ch = VERTICAL_LINE
- pts[i].Bg = l.BgColor
- pts[i].Fg = l.FgColor
- }
- return pts
-}
-
-// Draw a box border.
-func (b border) Buffer() []Point {
- if b.Width < 2 || b.Height < 2 {
- return nil
- }
- pts := make([]Point, 2*b.Width+2*b.Height-4)
-
- pts[0].X = b.X
- pts[0].Y = b.Y
- pts[0].Fg = b.FgColor
- pts[0].Bg = b.BgColor
- pts[0].Ch = TOP_LEFT
-
- pts[1].X = b.X + b.Width - 1
- pts[1].Y = b.Y
- pts[1].Fg = b.FgColor
- pts[1].Bg = b.BgColor
- pts[1].Ch = TOP_RIGHT
-
- pts[2].X = b.X
- pts[2].Y = b.Y + b.Height - 1
- pts[2].Fg = b.FgColor
- pts[2].Bg = b.BgColor
- pts[2].Ch = BOTTOM_LEFT
-
- pts[3].X = b.X + b.Width - 1
- pts[3].Y = b.Y + b.Height - 1
- pts[3].Fg = b.FgColor
- pts[3].Bg = b.BgColor
- pts[3].Ch = BOTTOM_RIGHT
-
- copy(pts[4:], (hline{b.X + 1, b.Y, b.Width - 2, b.FgColor, b.BgColor}).Buffer())
- copy(pts[4+b.Width-2:], (hline{b.X + 1, b.Y + b.Height - 1, b.Width - 2, b.FgColor, b.BgColor}).Buffer())
- copy(pts[4+2*b.Width-4:], (vline{b.X, b.Y + 1, b.Height - 2, b.FgColor, b.BgColor}).Buffer())
- copy(pts[4+2*b.Width-4+b.Height-2:], (vline{b.X + b.Width - 1, b.Y + 1, b.Height - 2, b.FgColor, b.BgColor}).Buffer())
-
- return pts
-}
-
-type labeledBorder struct {
- border
- Label string
- LabelFgColor Attribute
- LabelBgColor Attribute
-}
-
-// Draw a box border with label.
-func (lb labeledBorder) Buffer() []Point {
- ps := lb.border.Buffer()
- maxTxtW := lb.Width - 2
- rs := trimStr2Runes(lb.Label, maxTxtW)
-
- for i, j, w := 0, 0, 0; i < len(rs); i++ {
- w = charWidth(rs[i])
- ps = append(ps, newPointWithAttrs(rs[i], lb.X+1+j, lb.Y, lb.LabelFgColor, lb.LabelBgColor))
- j += w
- }
-
- return ps
-}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/buffer.go b/Godeps/_workspace/src/github.com/gizak/termui/buffer.go
new file mode 100644
index 000000000..60e77863a
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/buffer.go
@@ -0,0 +1,106 @@
+// Copyright 2016 Zack Guo <gizak@icloud.com>. All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+package termui
+
+import "image"
+
+// Cell is a rune with assigned Fg and Bg
+type Cell struct {
+ Ch rune
+ Fg Attribute
+ Bg Attribute
+}
+
+// Buffer is a renderable rectangle cell data container.
+type Buffer struct {
+ Area image.Rectangle // selected drawing area
+ CellMap map[image.Point]Cell
+}
+
+// At returns the cell at (x,y).
+func (b Buffer) At(x, y int) Cell {
+ return b.CellMap[image.Pt(x, y)]
+}
+
+// Set assigns a char to (x,y)
+func (b Buffer) Set(x, y int, c Cell) {
+ b.CellMap[image.Pt(x, y)] = c
+}
+
+// Bounds returns the domain for which At can return non-zero color.
+func (b Buffer) Bounds() image.Rectangle {
+ x0, y0, x1, y1 := 0, 0, 0, 0
+ for p := range b.CellMap {
+ if p.X > x1 {
+ x1 = p.X
+ }
+ if p.X < x0 {
+ x0 = p.X
+ }
+ if p.Y > y1 {
+ y1 = p.Y
+ }
+ if p.Y < y0 {
+ y0 = p.Y
+ }
+ }
+ return image.Rect(x0, y0, x1, y1)
+}
+
+// SetArea assigns a new rect area to Buffer b.
+func (b *Buffer) SetArea(r image.Rectangle) {
+ b.Area.Max = r.Max
+ b.Area.Min = r.Min
+}
+
+// Sync sets drawing area to the buffer's bound
+func (b Buffer) Sync() {
+ b.SetArea(b.Bounds())
+}
+
+// NewCell returns a new cell
+func NewCell(ch rune, fg, bg Attribute) Cell {
+ return Cell{ch, fg, bg}
+}
+
+// Merge merges bs Buffers onto b
+func (b *Buffer) Merge(bs ...Buffer) {
+ for _, buf := range bs {
+ for p, v := range buf.CellMap {
+ b.Set(p.X, p.Y, v)
+ }
+ b.SetArea(b.Area.Union(buf.Area))
+ }
+}
+
+// NewBuffer returns a new Buffer
+func NewBuffer() Buffer {
+ return Buffer{
+ CellMap: make(map[image.Point]Cell),
+ Area: image.Rectangle{}}
+}
+
+// Fill fills the Buffer b with ch,fg and bg.
+func (b Buffer) Fill(ch rune, fg, bg Attribute) {
+ for x := b.Area.Min.X; x < b.Area.Max.X; x++ {
+ for y := b.Area.Min.Y; y < b.Area.Max.Y; y++ {
+ b.Set(x, y, Cell{ch, fg, bg})
+ }
+ }
+}
+
+// NewFilledBuffer returns a new Buffer filled with ch, fb and bg.
+func NewFilledBuffer(x0, y0, x1, y1 int, ch rune, fg, bg Attribute) Buffer {
+ buf := NewBuffer()
+ buf.Area.Min = image.Pt(x0, y0)
+ buf.Area.Max = image.Pt(x1, y1)
+
+ for x := buf.Area.Min.X; x < buf.Area.Max.X; x++ {
+ for y := buf.Area.Min.Y; y < buf.Area.Max.Y; y++ {
+ buf.Set(x, y, Cell{ch, fg, bg})
+ }
+ }
+ return buf
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/canvas.go b/Godeps/_workspace/src/github.com/gizak/termui/canvas.go
index 614635ee4..4173780f3 100644
--- a/Godeps/_workspace/src/github.com/gizak/termui/canvas.go
+++ b/Godeps/_workspace/src/github.com/gizak/termui/canvas.go
@@ -1,4 +1,4 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
+// Copyright 2016 Zack Guo <gizak@icloud.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
@@ -63,12 +63,10 @@ func (c Canvas) Unset(x, y int) {
}
// Buffer returns un-styled points
-func (c Canvas) Buffer() []Point {
- ps := make([]Point, len(c))
- i := 0
+func (c Canvas) Buffer() Buffer {
+ buf := NewBuffer()
for k, v := range c {
- ps[i] = newPoint(v+brailleBase, k[0], k[1])
- i++
+ buf.Set(k[0], k[1], Cell{Ch: v + brailleBase})
}
- return ps
+ return buf
}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/canvas_test.go b/Godeps/_workspace/src/github.com/gizak/termui/canvas_test.go
deleted file mode 100644
index 021949ced..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/canvas_test.go
+++ /dev/null
@@ -1,55 +0,0 @@
-package termui
-
-import (
- "testing"
-
- "github.com/davecgh/go-spew/spew"
-)
-
-func TestCanvasSet(t *testing.T) {
- c := NewCanvas()
- c.Set(0, 0)
- c.Set(0, 1)
- c.Set(0, 2)
- c.Set(0, 3)
- c.Set(1, 3)
- c.Set(2, 3)
- c.Set(3, 3)
- c.Set(4, 3)
- c.Set(5, 3)
- spew.Dump(c)
-}
-
-func TestCanvasUnset(t *testing.T) {
- c := NewCanvas()
- c.Set(0, 0)
- c.Set(0, 1)
- c.Set(0, 2)
- c.Unset(0, 2)
- spew.Dump(c)
- c.Unset(0, 3)
- spew.Dump(c)
-}
-
-func TestCanvasBuffer(t *testing.T) {
- c := NewCanvas()
- c.Set(0, 0)
- c.Set(0, 1)
- c.Set(0, 2)
- c.Set(0, 3)
- c.Set(1, 3)
- c.Set(2, 3)
- c.Set(3, 3)
- c.Set(4, 3)
- c.Set(5, 3)
- c.Set(6, 3)
- c.Set(7, 2)
- c.Set(8, 1)
- c.Set(9, 0)
- bufs := c.Buffer()
- rs := make([]rune, len(bufs))
- for i, v := range bufs {
- rs[i] = v.Ch
- }
- spew.Dump(string(rs))
-}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/config b/Godeps/_workspace/src/github.com/gizak/termui/config
new file mode 100644
index 000000000..18fd6a401
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/config
@@ -0,0 +1,26 @@
+#!/usr/bin/env perl6
+
+use v6;
+
+my $copyright = '// Copyright 2016 Zack Guo <gizak@icloud.com>. All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+';
+
+sub MAIN('update-docstr', Str $srcp) {
+ if $srcp.IO.f {
+ $_ = $srcp.IO.slurp;
+ if m/^ \/\/\s Copyright .+? \n\n/ {
+ unless ~$/ eq $copyright {
+ s/^ \/\/\s Copyright .+? \n\n /$copyright/;
+ spurt $srcp, $_;
+ say "[updated] doc string for:"~$srcp;
+ }
+ } else {
+ say "[added] doc string for "~$srcp~" (no match found)";
+ $_ = $copyright ~ $_;
+ spurt $srcp, $_;
+ }
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/debug/debuger.go b/Godeps/_workspace/src/github.com/gizak/termui/debug/debuger.go
new file mode 100644
index 000000000..f723b9686
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/debug/debuger.go
@@ -0,0 +1,117 @@
+// Copyright 2016 Zack Guo <gizak@icloud.com>. All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+package debug
+
+import (
+ "fmt"
+ "net/http"
+
+ "golang.org/x/net/websocket"
+)
+
+type Server struct {
+ Port string
+ Addr string
+ Path string
+ Msg chan string
+ chs []chan string
+}
+
+type Client struct {
+ Port string
+ Addr string
+ Path string
+ ws *websocket.Conn
+}
+
+var defaultPort = ":8080"
+
+func NewServer() *Server {
+ return &Server{
+ Port: defaultPort,
+ Addr: "localhost",
+ Path: "/echo",
+ Msg: make(chan string),
+ chs: make([]chan string, 0),
+ }
+}
+
+func NewClient() Client {
+ return Client{
+ Port: defaultPort,
+ Addr: "localhost",
+ Path: "/echo",
+ }
+}
+
+func (c Client) ConnectAndListen() error {
+ ws, err := websocket.Dial("ws://"+c.Addr+c.Port+c.Path, "", "http://"+c.Addr)
+ if err != nil {
+ return err
+ }
+ defer ws.Close()
+
+ var m string
+ for {
+ err := websocket.Message.Receive(ws, &m)
+ if err != nil {
+ fmt.Print(err)
+ return err
+ }
+ fmt.Print(m)
+ }
+}
+
+func (s *Server) ListenAndServe() error {
+ http.Handle(s.Path, websocket.Handler(func(ws *websocket.Conn) {
+ defer ws.Close()
+
+ mc := make(chan string)
+ s.chs = append(s.chs, mc)
+
+ for m := range mc {
+ websocket.Message.Send(ws, m)
+ }
+ }))
+
+ go func() {
+ for msg := range s.Msg {
+ for _, c := range s.chs {
+ go func(a chan string) {
+ a <- msg
+ }(c)
+ }
+ }
+ }()
+
+ return http.ListenAndServe(s.Port, nil)
+}
+
+func (s *Server) Log(msg string) {
+ go func() { s.Msg <- msg }()
+}
+
+func (s *Server) Logf(format string, a ...interface{}) {
+ s.Log(fmt.Sprintf(format, a...))
+}
+
+var DefaultServer = NewServer()
+var DefaultClient = NewClient()
+
+func ListenAndServe() error {
+ return DefaultServer.ListenAndServe()
+}
+
+func ConnectAndListen() error {
+ return DefaultClient.ConnectAndListen()
+}
+
+func Log(msg string) {
+ DefaultServer.Log(msg)
+}
+
+func Logf(format string, a ...interface{}) {
+ DefaultServer.Logf(format, a...)
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/doc.go b/Godeps/_workspace/src/github.com/gizak/termui/doc.go
index 43f886f55..b80e46415 100644
--- a/Godeps/_workspace/src/github.com/gizak/termui/doc.go
+++ b/Godeps/_workspace/src/github.com/gizak/termui/doc.go
@@ -1,4 +1,4 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
+// Copyright 2016 Zack Guo <gizak@icloud.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/events.go b/Godeps/_workspace/src/github.com/gizak/termui/events.go
index 23a189b56..177bbb4b0 100644
--- a/Godeps/_workspace/src/github.com/gizak/termui/events.go
+++ b/Godeps/_workspace/src/github.com/gizak/termui/events.go
@@ -1,219 +1,316 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
+// Copyright 2016 Zack Guo <gizak@icloud.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
-//
-// Portions of this file uses [termbox-go](https://github.com/nsf/termbox-go/blob/54b74d087b7c397c402d0e3b66d2ccb6eaf5c2b4/api_common.go)
-// by [authors](https://github.com/nsf/termbox-go/blob/master/AUTHORS)
-// under [license](https://github.com/nsf/termbox-go/blob/master/LICENSE)
package termui
-import "github.com/nsf/termbox-go"
+import (
+ "path"
+ "strconv"
+ "sync"
+ "time"
-/***********************************termbox-go**************************************/
-
-type (
- EventType uint8
- Modifier uint8
- Key uint16
+ "github.com/nsf/termbox-go"
)
-// This type represents a termbox event. The 'Mod', 'Key' and 'Ch' fields are
-// valid if 'Type' is EventKey. The 'Width' and 'Height' fields are valid if
-// 'Type' is EventResize. The 'Err' field is valid if 'Type' is EventError.
type Event struct {
- Type EventType // one of Event* constants
- Mod Modifier // one of Mod* constants or 0
- Key Key // one of Key* constants, invalid if 'Ch' is not 0
- Ch rune // a unicode character
- Width int // width of the screen
- Height int // height of the screen
- Err error // error in case if input failed
- MouseX int // x coord of mouse
- MouseY int // y coord of mouse
- N int // number of bytes written when getting a raw event
-}
-
-const (
- KeyF1 Key = 0xFFFF - iota
- KeyF2
- KeyF3
- KeyF4
- KeyF5
- KeyF6
- KeyF7
- KeyF8
- KeyF9
- KeyF10
- KeyF11
- KeyF12
- KeyInsert
- KeyDelete
- KeyHome
- KeyEnd
- KeyPgup
- KeyPgdn
- KeyArrowUp
- KeyArrowDown
- KeyArrowLeft
- KeyArrowRight
- key_min // see terminfo
- MouseLeft
- MouseMiddle
- MouseRight
-)
+ Type string
+ Path string
+ From string
+ To string
+ Data interface{}
+ Time int64
+}
-const (
- KeyCtrlTilde Key = 0x00
- KeyCtrl2 Key = 0x00
- KeyCtrlSpace Key = 0x00
- KeyCtrlA Key = 0x01
- KeyCtrlB Key = 0x02
- KeyCtrlC Key = 0x03
- KeyCtrlD Key = 0x04
- KeyCtrlE Key = 0x05
- KeyCtrlF Key = 0x06
- KeyCtrlG Key = 0x07
- KeyBackspace Key = 0x08
- KeyCtrlH Key = 0x08
- KeyTab Key = 0x09
- KeyCtrlI Key = 0x09
- KeyCtrlJ Key = 0x0A
- KeyCtrlK Key = 0x0B
- KeyCtrlL Key = 0x0C
- KeyEnter Key = 0x0D
- KeyCtrlM Key = 0x0D
- KeyCtrlN Key = 0x0E
- KeyCtrlO Key = 0x0F
- KeyCtrlP Key = 0x10
- KeyCtrlQ Key = 0x11
- KeyCtrlR Key = 0x12
- KeyCtrlS Key = 0x13
- KeyCtrlT Key = 0x14
- KeyCtrlU Key = 0x15
- KeyCtrlV Key = 0x16
- KeyCtrlW Key = 0x17
- KeyCtrlX Key = 0x18
- KeyCtrlY Key = 0x19
- KeyCtrlZ Key = 0x1A
- KeyEsc Key = 0x1B
- KeyCtrlLsqBracket Key = 0x1B
- KeyCtrl3 Key = 0x1B
- KeyCtrl4 Key = 0x1C
- KeyCtrlBackslash Key = 0x1C
- KeyCtrl5 Key = 0x1D
- KeyCtrlRsqBracket Key = 0x1D
- KeyCtrl6 Key = 0x1E
- KeyCtrl7 Key = 0x1F
- KeyCtrlSlash Key = 0x1F
- KeyCtrlUnderscore Key = 0x1F
- KeySpace Key = 0x20
- KeyBackspace2 Key = 0x7F
- KeyCtrl8 Key = 0x7F
-)
+var sysEvtChs []chan Event
-// Alt modifier constant, see Event.Mod field and SetInputMode function.
-const (
- ModAlt Modifier = 0x01
-)
+type EvtKbd struct {
+ KeyStr string
+}
-// Event type. See Event.Type field.
-const (
- EventKey EventType = iota
- EventResize
- EventMouse
- EventError
- EventInterrupt
- EventRaw
- EventNone
-)
+func evtKbd(e termbox.Event) EvtKbd {
+ ek := EvtKbd{}
-/**************************************end**************************************/
+ k := string(e.Ch)
+ pre := ""
+ mod := ""
-// convert termbox.Event to termui.Event
-func uiEvt(e termbox.Event) Event {
- event := Event{}
- event.Type = EventType(e.Type)
- event.Mod = Modifier(e.Mod)
- event.Key = Key(e.Key)
- event.Ch = e.Ch
- event.Width = e.Width
- event.Height = e.Height
- event.Err = e.Err
- event.MouseX = e.MouseX
- event.MouseY = e.MouseY
- event.N = e.N
+ if e.Mod == termbox.ModAlt {
+ mod = "M-"
+ }
+ if e.Ch == 0 {
+ if e.Key > 0xFFFF-12 {
+ k = "<f" + strconv.Itoa(0xFFFF-int(e.Key)+1) + ">"
+ } else if e.Key > 0xFFFF-25 {
+ ks := []string{"<insert>", "<delete>", "<home>", "<end>", "<previous>", "<next>", "<up>", "<down>", "<left>", "<right>"}
+ k = ks[0xFFFF-int(e.Key)-12]
+ }
- return event
+ if e.Key <= 0x7F {
+ pre = "C-"
+ k = string('a' - 1 + int(e.Key))
+ kmap := map[termbox.Key][2]string{
+ termbox.KeyCtrlSpace: {"C-", "<space>"},
+ termbox.KeyBackspace: {"", "<backspace>"},
+ termbox.KeyTab: {"", "<tab>"},
+ termbox.KeyEnter: {"", "<enter>"},
+ termbox.KeyEsc: {"", "<escape>"},
+ termbox.KeyCtrlBackslash: {"C-", "\\"},
+ termbox.KeyCtrlSlash: {"C-", "/"},
+ termbox.KeySpace: {"", "<space>"},
+ termbox.KeyCtrl8: {"C-", "8"},
+ }
+ if sk, ok := kmap[e.Key]; ok {
+ pre = sk[0]
+ k = sk[1]
+ }
+ }
+ }
+
+ ek.KeyStr = pre + mod + k
+ return ek
}
-var evtChs = make([]chan Event, 0)
+func crtTermboxEvt(e termbox.Event) Event {
+ systypemap := map[termbox.EventType]string{
+ termbox.EventKey: "keyboard",
+ termbox.EventResize: "window",
+ termbox.EventMouse: "mouse",
+ termbox.EventError: "error",
+ termbox.EventInterrupt: "interrupt",
+ }
+ ne := Event{From: "/sys", Time: time.Now().Unix()}
+ typ := e.Type
+ ne.Type = systypemap[typ]
+
+ switch typ {
+ case termbox.EventKey:
+ kbd := evtKbd(e)
+ ne.Path = "/sys/kbd/" + kbd.KeyStr
+ ne.Data = kbd
+ case termbox.EventResize:
+ wnd := EvtWnd{}
+ wnd.Width = e.Width
+ wnd.Height = e.Height
+ ne.Path = "/sys/wnd/resize"
+ ne.Data = wnd
+ case termbox.EventError:
+ err := EvtErr(e.Err)
+ ne.Path = "/sys/err"
+ ne.Data = err
+ case termbox.EventMouse:
+ m := EvtMouse{}
+ m.X = e.MouseX
+ m.Y = e.MouseY
+ ne.Path = "/sys/mouse"
+ ne.Data = m
+ }
+ return ne
+}
-// EventCh returns an output-only event channel.
-// This function can be called many times (multiplexer).
-func EventCh() <-chan Event {
- out := make(chan Event)
- evtChs = append(evtChs, out)
- return out
+type EvtWnd struct {
+ Width int
+ Height int
}
-// turn on event listener
-func evtListen() {
- go func() {
- for {
- e := termbox.PollEvent()
- // dispatch
- for _, c := range evtChs {
- go func(ch chan Event) {
- ch <- uiEvt(e)
- }(c)
- }
+type EvtMouse struct {
+ X int
+ Y int
+ Press string
+}
+
+type EvtErr error
+
+func hookTermboxEvt() {
+ for {
+ e := termbox.PollEvent()
+
+ for _, c := range sysEvtChs {
+ go func(ch chan Event) {
+ ch <- crtTermboxEvt(e)
+ }(c)
}
+ }
+}
+
+func NewSysEvtCh() chan Event {
+ ec := make(chan Event)
+ sysEvtChs = append(sysEvtChs, ec)
+ return ec
+}
+
+var DefaultEvtStream = NewEvtStream()
+
+type EvtStream struct {
+ sync.RWMutex
+ srcMap map[string]chan Event
+ stream chan Event
+ wg sync.WaitGroup
+ sigStopLoop chan Event
+ Handlers map[string]func(Event)
+ hook func(Event)
+}
+
+func NewEvtStream() *EvtStream {
+ return &EvtStream{
+ srcMap: make(map[string]chan Event),
+ stream: make(chan Event),
+ Handlers: make(map[string]func(Event)),
+ sigStopLoop: make(chan Event),
+ }
+}
+
+func (es *EvtStream) Init() {
+ es.Merge("internal", es.sigStopLoop)
+ go func() {
+ es.wg.Wait()
+ close(es.stream)
}()
}
-/*
-// EventHandlers is a handler sequence
-var EventHandlers []func(Event)
+func cleanPath(p string) string {
+ if p == "" {
+ return "/"
+ }
+ if p[0] != '/' {
+ p = "/" + p
+ }
+ return path.Clean(p)
+}
-var signalQuit = make(chan bool)
+func isPathMatch(pattern, path string) bool {
+ if len(pattern) == 0 {
+ return false
+ }
+ n := len(pattern)
+ return len(path) >= n && path[0:n] == pattern
+}
+
+func (es *EvtStream) Merge(name string, ec chan Event) {
+ es.Lock()
+ defer es.Unlock()
+
+ es.wg.Add(1)
+ es.srcMap[name] = ec
-// Quit sends quit signal to terminate termui
-func Quit() {
- signalQuit <- true
+ go func(a chan Event) {
+ for n := range a {
+ n.From = name
+ es.stream <- n
+ }
+ es.wg.Done()
+ }(ec)
}
-// Wait listening to signalQuit, block operation.
-func Wait() {
- <-signalQuit
+func (es *EvtStream) Handle(path string, handler func(Event)) {
+ es.Handlers[cleanPath(path)] = handler
}
-// RegEvtHandler register function into TSEventHandler sequence.
-func RegEvtHandler(fn func(Event)) {
- EventHandlers = append(EventHandlers, fn)
+func findMatch(mux map[string]func(Event), path string) string {
+ n := -1
+ pattern := ""
+ for m := range mux {
+ if !isPathMatch(m, path) {
+ continue
+ }
+ if len(m) > n {
+ pattern = m
+ n = len(m)
+ }
+ }
+ return pattern
+
}
-// EventLoop handles all events and
-// redirects every event to callbacks in EventHandlers
-func EventLoop() {
- evt := make(chan termbox.Event)
+func (es *EvtStream) match(path string) string {
+ return findMatch(es.Handlers, path)
+}
+
+func (es *EvtStream) Hook(f func(Event)) {
+ es.hook = f
+}
+func (es *EvtStream) Loop() {
+ for e := range es.stream {
+ switch e.Path {
+ case "/sig/stoploop":
+ return
+ }
+ go func(a Event) {
+ es.RLock()
+ defer es.RUnlock()
+ if pattern := es.match(a.Path); pattern != "" {
+ es.Handlers[pattern](a)
+ }
+ }(e)
+ if es.hook != nil {
+ es.hook(e)
+ }
+ }
+}
+
+func (es *EvtStream) StopLoop() {
go func() {
- for {
- evt <- termbox.PollEvent()
+ e := Event{
+ Path: "/sig/stoploop",
}
+ es.sigStopLoop <- e
}()
+}
- for {
- select {
- case c := <-signalQuit:
- defer func() { signalQuit <- c }()
- return
- case e := <-evt:
- for _, fn := range EventHandlers {
- fn(uiEvt(e))
+func Merge(name string, ec chan Event) {
+ DefaultEvtStream.Merge(name, ec)
+}
+
+func Handle(path string, handler func(Event)) {
+ DefaultEvtStream.Handle(path, handler)
+}
+
+func Loop() {
+ DefaultEvtStream.Loop()
+}
+
+func StopLoop() {
+ DefaultEvtStream.StopLoop()
+}
+
+type EvtTimer struct {
+ Duration time.Duration
+ Count uint64
+}
+
+func NewTimerCh(du time.Duration) chan Event {
+ t := make(chan Event)
+
+ go func(a chan Event) {
+ n := uint64(0)
+ for {
+ n++
+ time.Sleep(du)
+ e := Event{}
+ e.Type = "timer"
+ e.Path = "/timer/" + du.String()
+ e.Time = time.Now().Unix()
+ e.Data = EvtTimer{
+ Duration: du,
+ Count: n,
}
+ t <- e
+
}
- }
+ }(t)
+ return t
+}
+
+var DefualtHandler = func(e Event) {
+}
+
+var usrEvtCh = make(chan Event)
+
+func SendCustomEvt(path string, data interface{}) {
+ e := Event{}
+ e.Path = path
+ e.Data = data
+ e.Time = time.Now().Unix()
+ usrEvtCh <- e
}
-*/
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/events_test.go b/Godeps/_workspace/src/github.com/gizak/termui/events_test.go
deleted file mode 100644
index 1137b1d26..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/events_test.go
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
-// Use of this source code is governed by a MIT license that can
-// be found in the LICENSE file.
-//
-// Portions of this file uses [termbox-go](https://github.com/nsf/termbox-go/blob/54b74d087b7c397c402d0e3b66d2ccb6eaf5c2b4/api_common.go)
-// by [authors](https://github.com/nsf/termbox-go/blob/master/AUTHORS)
-// under [license](https://github.com/nsf/termbox-go/blob/master/LICENSE)
-
-package termui
-
-import (
- "errors"
- "testing"
-
- termbox "github.com/nsf/termbox-go"
- "github.com/stretchr/testify/assert"
-)
-
-type boxEvent termbox.Event
-
-func TestUiEvt(t *testing.T) {
- err := errors.New("This is a mock error")
- event := boxEvent{3, 5, 2, 'H', 200, 500, err, 50, 30, 2}
- expetced := Event{3, 5, 2, 'H', 200, 500, err, 50, 30, 2}
-
- // We need to do that ugly casting so that vet does not complain
- assert.Equal(t, uiEvt(termbox.Event(event)), expetced)
-}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/barchart.go b/Godeps/_workspace/src/github.com/gizak/termui/example/barchart.go
deleted file mode 100644
index 83947f580..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/example/barchart.go
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
-// Use of this source code is governed by a MIT license that can
-// be found in the LICENSE file.
-
-// +build ignore
-
-package main
-
-import "github.com/gizak/termui"
-
-func main() {
- err := termui.Init()
- if err != nil {
- panic(err)
- }
- defer termui.Close()
-
- termui.UseTheme("helloworld")
-
- bc := termui.NewBarChart()
- data := []int{3, 2, 5, 3, 9, 5, 3, 2, 5, 8, 3, 2, 4, 5, 3, 2, 5, 7, 5, 3, 2, 6, 7, 4, 6, 3, 6, 7, 8, 3, 6, 4, 5, 3, 2, 4, 6, 4, 8, 5, 9, 4, 3, 6, 5, 3, 6}
- bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"}
- bc.Border.Label = "Bar Chart"
- bc.Data = data
- bc.Width = 26
- bc.Height = 10
- bc.DataLabels = bclabels
- bc.TextColor = termui.ColorGreen
- bc.BarColor = termui.ColorRed
- bc.NumColor = termui.ColorYellow
-
- termui.Render(bc)
-
- <-termui.EventCh()
-}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/barchart.png b/Godeps/_workspace/src/github.com/gizak/termui/example/barchart.png
deleted file mode 100644
index a37912f7f..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/example/barchart.png
+++ /dev/null
Binary files differ
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/dashboard.gif b/Godeps/_workspace/src/github.com/gizak/termui/example/dashboard.gif
deleted file mode 100644
index 8e1859c72..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/example/dashboard.gif
+++ /dev/null
Binary files differ
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/dashboard.go b/Godeps/_workspace/src/github.com/gizak/termui/example/dashboard.go
deleted file mode 100644
index c14bb4413..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/example/dashboard.go
+++ /dev/null
@@ -1,148 +0,0 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
-// Use of this source code is governed by a MIT license that can
-// be found in the LICENSE file.
-
-// +build ignore
-
-package main
-
-import ui "github.com/gizak/termui"
-import "math"
-
-import "time"
-
-func main() {
- err := ui.Init()
- if err != nil {
- panic(err)
- }
- defer ui.Close()
-
- p := ui.NewPar(":PRESS q TO QUIT DEMO")
- p.Height = 3
- p.Width = 50
- p.TextFgColor = ui.ColorWhite
- p.Border.Label = "Text Box"
- p.Border.FgColor = ui.ColorCyan
-
- strs := []string{"[0] gizak/termui", "[1] editbox.go", "[2] iterrupt.go", "[3] keyboard.go", "[4] output.go", "[5] random_out.go", "[6] dashboard.go", "[7] nsf/termbox-go"}
- list := ui.NewList()
- list.Items = strs
- list.ItemFgColor = ui.ColorYellow
- list.Border.Label = "List"
- list.Height = 7
- list.Width = 25
- list.Y = 4
-
- g := ui.NewGauge()
- g.Percent = 50
- g.Width = 50
- g.Height = 3
- g.Y = 11
- g.Border.Label = "Gauge"
- g.BarColor = ui.ColorRed
- g.Border.FgColor = ui.ColorWhite
- g.Border.LabelFgColor = ui.ColorCyan
-
- spark := ui.Sparkline{}
- spark.Height = 1
- spark.Title = "srv 0:"
- spdata := []int{4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6, 4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6, 4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6, 4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6}
- spark.Data = spdata
- spark.LineColor = ui.ColorCyan
- spark.TitleColor = ui.ColorWhite
-
- spark1 := ui.Sparkline{}
- spark1.Height = 1
- spark1.Title = "srv 1:"
- spark1.Data = spdata
- spark1.TitleColor = ui.ColorWhite
- spark1.LineColor = ui.ColorRed
-
- sp := ui.NewSparklines(spark, spark1)
- sp.Width = 25
- sp.Height = 7
- sp.Border.Label = "Sparkline"
- sp.Y = 4
- sp.X = 25
-
- sinps := (func() []float64 {
- n := 220
- ps := make([]float64, n)
- for i := range ps {
- ps[i] = 1 + math.Sin(float64(i)/5)
- }
- return ps
- })()
-
- lc := ui.NewLineChart()
- lc.Border.Label = "dot-mode Line Chart"
- lc.Data = sinps
- lc.Width = 50
- lc.Height = 11
- lc.X = 0
- lc.Y = 14
- lc.AxesColor = ui.ColorWhite
- lc.LineColor = ui.ColorRed | ui.AttrBold
- lc.Mode = "dot"
-
- bc := ui.NewBarChart()
- bcdata := []int{3, 2, 5, 3, 9, 5, 3, 2, 5, 8, 3, 2, 4, 5, 3, 2, 5, 7, 5, 3, 2, 6, 7, 4, 6, 3, 6, 7, 8, 3, 6, 4, 5, 3, 2, 4, 6, 4, 8, 5, 9, 4, 3, 6, 5, 3, 6}
- bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"}
- bc.Border.Label = "Bar Chart"
- bc.Width = 26
- bc.Height = 10
- bc.X = 51
- bc.Y = 0
- bc.DataLabels = bclabels
- bc.BarColor = ui.ColorGreen
- bc.NumColor = ui.ColorBlack
-
- lc1 := ui.NewLineChart()
- lc1.Border.Label = "braille-mode Line Chart"
- lc1.Data = sinps
- lc1.Width = 26
- lc1.Height = 11
- lc1.X = 51
- lc1.Y = 14
- lc1.AxesColor = ui.ColorWhite
- lc1.LineColor = ui.ColorYellow | ui.AttrBold
-
- p1 := ui.NewPar("Hey!\nI am a borderless block!")
- p1.HasBorder = false
- p1.Width = 26
- p1.Height = 2
- p1.TextFgColor = ui.ColorMagenta
- p1.X = 52
- p1.Y = 11
-
- draw := func(t int) {
- g.Percent = t % 101
- list.Items = strs[t%9:]
- sp.Lines[0].Data = spdata[:30+t%50]
- sp.Lines[1].Data = spdata[:35+t%50]
- lc.Data = sinps[t/2:]
- lc1.Data = sinps[2*t:]
- bc.Data = bcdata[t/2%10:]
- ui.Render(p, list, g, sp, lc, bc, lc1, p1)
- }
-
- evt := ui.EventCh()
-
- i := 0
- for {
- select {
- case e := <-evt:
- if e.Type == ui.EventKey && e.Ch == 'q' {
- return
- }
- default:
- draw(i)
- i++
- if i == 102 {
- return
- }
- time.Sleep(time.Second / 2)
- }
- }
-}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/gauge.go b/Godeps/_workspace/src/github.com/gizak/termui/example/gauge.go
deleted file mode 100644
index b7033580f..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/example/gauge.go
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
-// Use of this source code is governed by a MIT license that can
-// be found in the LICENSE file.
-
-// +build ignore
-
-package main
-
-import "github.com/gizak/termui"
-
-func main() {
- err := termui.Init()
- if err != nil {
- panic(err)
- }
- defer termui.Close()
-
- termui.UseTheme("helloworld")
-
- g0 := termui.NewGauge()
- g0.Percent = 40
- g0.Width = 50
- g0.Height = 3
- g0.Border.Label = "Slim Gauge"
- g0.BarColor = termui.ColorRed
- g0.Border.FgColor = termui.ColorWhite
- g0.Border.LabelFgColor = termui.ColorCyan
-
- g2 := termui.NewGauge()
- g2.Percent = 60
- g2.Width = 50
- g2.Height = 3
- g2.PercentColor = termui.ColorBlue
- g2.Y = 3
- g2.Border.Label = "Slim Gauge"
- g2.BarColor = termui.ColorYellow
- g2.Border.FgColor = termui.ColorWhite
-
- g1 := termui.NewGauge()
- g1.Percent = 30
- g1.Width = 50
- g1.Height = 5
- g1.Y = 6
- g1.Border.Label = "Big Gauge"
- g1.PercentColor = termui.ColorYellow
- g1.BarColor = termui.ColorGreen
- g1.Border.FgColor = termui.ColorWhite
- g1.Border.LabelFgColor = termui.ColorMagenta
-
- g3 := termui.NewGauge()
- g3.Percent = 50
- g3.Width = 50
- g3.Height = 3
- g3.Y = 11
- g3.Border.Label = "Gauge with custom label"
- g3.Label = "{{percent}}% (100MBs free)"
- g3.LabelAlign = termui.AlignRight
-
- termui.Render(g0, g1, g2, g3)
-
- <-termui.EventCh()
-}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/gauge.png b/Godeps/_workspace/src/github.com/gizak/termui/example/gauge.png
deleted file mode 100644
index 5c20e6e8a..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/example/gauge.png
+++ /dev/null
Binary files differ
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/grid.gif b/Godeps/_workspace/src/github.com/gizak/termui/example/grid.gif
deleted file mode 100644
index 7490043de..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/example/grid.gif
+++ /dev/null
Binary files differ
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/grid.go b/Godeps/_workspace/src/github.com/gizak/termui/example/grid.go
deleted file mode 100644
index 49121411f..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/example/grid.go
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
-// Use of this source code is governed by a MIT license that can
-// be found in the LICENSE file.
-
-// +build ignore
-
-package main
-
-import ui "github.com/gizak/termui"
-import "math"
-import "time"
-
-func main() {
- err := ui.Init()
- if err != nil {
- panic(err)
- }
- defer ui.Close()
-
- sinps := (func() []float64 {
- n := 400
- ps := make([]float64, n)
- for i := range ps {
- ps[i] = 1 + math.Sin(float64(i)/5)
- }
- return ps
- })()
- sinpsint := (func() []int {
- ps := make([]int, len(sinps))
- for i, v := range sinps {
- ps[i] = int(100*v + 10)
- }
- return ps
- })()
-
- ui.UseTheme("helloworld")
-
- spark := ui.Sparkline{}
- spark.Height = 8
- spdata := sinpsint
- spark.Data = spdata[:100]
- spark.LineColor = ui.ColorCyan
- spark.TitleColor = ui.ColorWhite
-
- sp := ui.NewSparklines(spark)
- sp.Height = 11
- sp.Border.Label = "Sparkline"
-
- lc := ui.NewLineChart()
- lc.Border.Label = "braille-mode Line Chart"
- lc.Data = sinps
- lc.Height = 11
- lc.AxesColor = ui.ColorWhite
- lc.LineColor = ui.ColorYellow | ui.AttrBold
-
- gs := make([]*ui.Gauge, 3)
- for i := range gs {
- gs[i] = ui.NewGauge()
- gs[i].Height = 2
- gs[i].HasBorder = false
- gs[i].Percent = i * 10
- gs[i].PaddingBottom = 1
- gs[i].BarColor = ui.ColorRed
- }
-
- ls := ui.NewList()
- ls.HasBorder = false
- ls.Items = []string{
- "[1] Downloading File 1",
- "", // == \newline
- "[2] Downloading File 2",
- "",
- "[3] Uploading File 3",
- }
- ls.Height = 5
-
- par := ui.NewPar("<> This row has 3 columns\n<- Widgets can be stacked up like left side\n<- Stacked widgets are treated as a single widget")
- par.Height = 5
- par.Border.Label = "Demonstration"
-
- // build layout
- ui.Body.AddRows(
- ui.NewRow(
- ui.NewCol(6, 0, sp),
- ui.NewCol(6, 0, lc)),
- ui.NewRow(
- ui.NewCol(3, 0, ls),
- ui.NewCol(3, 0, gs[0], gs[1], gs[2]),
- ui.NewCol(6, 0, par)))
-
- // calculate layout
- ui.Body.Align()
-
- done := make(chan bool)
- redraw := make(chan bool)
-
- update := func() {
- for i := 0; i < 103; i++ {
- for _, g := range gs {
- g.Percent = (g.Percent + 3) % 100
- }
-
- sp.Lines[0].Data = spdata[:100+i]
- lc.Data = sinps[2*i:]
-
- time.Sleep(time.Second / 2)
- redraw <- true
- }
- done <- true
- }
-
- evt := ui.EventCh()
-
- ui.Render(ui.Body)
- go update()
-
- for {
- select {
- case e := <-evt:
- if e.Type == ui.EventKey && e.Ch == 'q' {
- return
- }
- if e.Type == ui.EventResize {
- ui.Body.Width = ui.TermWidth()
- ui.Body.Align()
- go func() { redraw <- true }()
- }
- case <-done:
- return
- case <-redraw:
- ui.Render(ui.Body)
- }
- }
-}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/linechart.go b/Godeps/_workspace/src/github.com/gizak/termui/example/linechart.go
deleted file mode 100644
index 1db543496..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/example/linechart.go
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
-// Use of this source code is governed by a MIT license that can
-// be found in the LICENSE file.
-
-// +build ignore
-
-package main
-
-import (
- "math"
-
- "github.com/gizak/termui"
-)
-
-func main() {
- err := termui.Init()
- if err != nil {
- panic(err)
- }
- defer termui.Close()
-
- termui.UseTheme("helloworld")
-
- sinps := (func() []float64 {
- n := 220
- ps := make([]float64, n)
- for i := range ps {
- ps[i] = 1 + math.Sin(float64(i)/5)
- }
- return ps
- })()
-
- lc0 := termui.NewLineChart()
- lc0.Border.Label = "braille-mode Line Chart"
- lc0.Data = sinps
- lc0.Width = 50
- lc0.Height = 12
- lc0.X = 0
- lc0.Y = 0
- lc0.AxesColor = termui.ColorWhite
- lc0.LineColor = termui.ColorGreen | termui.AttrBold
-
- lc1 := termui.NewLineChart()
- lc1.Border.Label = "dot-mode Line Chart"
- lc1.Mode = "dot"
- lc1.Data = sinps
- lc1.Width = 26
- lc1.Height = 12
- lc1.X = 51
- lc1.DotStyle = '+'
- lc1.AxesColor = termui.ColorWhite
- lc1.LineColor = termui.ColorYellow | termui.AttrBold
-
- lc2 := termui.NewLineChart()
- lc2.Border.Label = "dot-mode Line Chart"
- lc2.Mode = "dot"
- lc2.Data = sinps[4:]
- lc2.Width = 77
- lc2.Height = 16
- lc2.X = 0
- lc2.Y = 12
- lc2.AxesColor = termui.ColorWhite
- lc2.LineColor = termui.ColorCyan | termui.AttrBold
-
- termui.Render(lc0, lc1, lc2)
-
- <-termui.EventCh()
-}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/linechart.png b/Godeps/_workspace/src/github.com/gizak/termui/example/linechart.png
deleted file mode 100644
index 655ef435f..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/example/linechart.png
+++ /dev/null
Binary files differ
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/list.go b/Godeps/_workspace/src/github.com/gizak/termui/example/list.go
deleted file mode 100644
index d33a3616c..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/example/list.go
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
-// Use of this source code is governed by a MIT license that can
-// be found in the LICENSE file.
-
-// +build ignore
-
-package main
-
-import "github.com/gizak/termui"
-
-func main() {
- err := termui.Init()
- if err != nil {
- panic(err)
- }
- defer termui.Close()
-
- termui.UseTheme("helloworld")
-
- strs := []string{
- "[0] github.com/gizak/termui",
- "[1] 你好,世界",
- "[2] こんにちは世界",
- "[3] keyboard.go",
- "[4] output.go",
- "[5] random_out.go",
- "[6] dashboard.go",
- "[7] nsf/termbox-go"}
-
- ls := termui.NewList()
- ls.Items = strs
- ls.ItemFgColor = termui.ColorYellow
- ls.Border.Label = "List"
- ls.Height = 7
- ls.Width = 25
- ls.Y = 0
-
- termui.Render(ls)
-
- <-termui.EventCh()
-}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/list.png b/Godeps/_workspace/src/github.com/gizak/termui/example/list.png
deleted file mode 100644
index 8ca08c079..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/example/list.png
+++ /dev/null
Binary files differ
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/mbarchart.go b/Godeps/_workspace/src/github.com/gizak/termui/example/mbarchart.go
deleted file mode 100644
index a32a28e0a..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/example/mbarchart.go
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
-// Use of this source code is governed by a MIT license that can
-// be found in the LICENSE file.
-
-// +build ignore
-
-package main
-
-import "github.com/gizak/termui"
-
-func main() {
- err := termui.Init()
- if err != nil {
- panic(err)
- }
- defer termui.Close()
-
- termui.UseTheme("helloworld")
-
- bc := termui.NewMBarChart()
- math := []int{90, 85, 90, 80}
- english := []int{70, 85, 75, 60}
- science := []int{75, 60, 80, 85}
- compsci := []int{100, 100, 100, 100}
- bc.Data[0] = math
- bc.Data[1] = english
- bc.Data[2] = science
- bc.Data[3] = compsci
- studentsName := []string{"Ken", "Rob", "Dennis", "Linus"}
- bc.Border.Label = "Student's Marks X-Axis=Name Y-Axis=Marks[Math,English,Science,ComputerScience] in %"
- bc.Width = 100
- bc.Height = 50
- bc.Y = 10
- bc.BarWidth = 10
- bc.DataLabels = studentsName
- bc.ShowScale = true //Show y_axis scale value (min and max)
- bc.SetMax(400)
-
- bc.TextColor = termui.ColorGreen //this is color for label (x-axis)
- bc.BarColor[3] = termui.ColorGreen //BarColor for computerscience
- bc.BarColor[1] = termui.ColorYellow //Bar Color for english
- bc.NumColor[3] = termui.ColorRed // Num color for computerscience
- bc.NumColor[1] = termui.ColorRed // num color for english
-
- //Other colors are automatically populated, btw All the students seems do well in computerscience. :p
-
- termui.Render(bc)
-
- <-termui.EventCh()
-}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/mbarchart.png b/Godeps/_workspace/src/github.com/gizak/termui/example/mbarchart.png
deleted file mode 100644
index 9a4252616..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/example/mbarchart.png
+++ /dev/null
Binary files differ
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/par.go b/Godeps/_workspace/src/github.com/gizak/termui/example/par.go
deleted file mode 100644
index ffbc60aa8..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/example/par.go
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
-// Use of this source code is governed by a MIT license that can
-// be found in the LICENSE file.
-
-// +build ignore
-
-package main
-
-import "github.com/gizak/termui"
-
-func main() {
- err := termui.Init()
- if err != nil {
- panic(err)
- }
- defer termui.Close()
-
- termui.UseTheme("helloworld")
-
- par0 := termui.NewPar("Borderless Text")
- par0.Height = 1
- par0.Width = 20
- par0.Y = 1
- par0.HasBorder = false
-
- par1 := termui.NewPar("你好,世界。")
- par1.Height = 3
- par1.Width = 17
- par1.X = 20
- par1.Border.Label = "标签"
-
- par2 := termui.NewPar("Simple text\nwith label. It can be multilined with \\n or break automatically")
- par2.Height = 5
- par2.Width = 37
- par2.Y = 4
- par2.Border.Label = "Multiline"
- par2.Border.FgColor = termui.ColorYellow
-
- par3 := termui.NewPar("Long text with label and it is auto trimmed.")
- par3.Height = 3
- par3.Width = 37
- par3.Y = 9
- par3.Border.Label = "Auto Trim"
-
- termui.Render(par0, par1, par2, par3)
-
- <-termui.EventCh()
-}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/par.png b/Godeps/_workspace/src/github.com/gizak/termui/example/par.png
deleted file mode 100644
index a85e64415..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/example/par.png
+++ /dev/null
Binary files differ
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/sparklines.go b/Godeps/_workspace/src/github.com/gizak/termui/example/sparklines.go
deleted file mode 100644
index f04baf570..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/example/sparklines.go
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
-// Use of this source code is governed by a MIT license that can
-// be found in the LICENSE file.
-
-// +build ignore
-
-package main
-
-import "github.com/gizak/termui"
-
-func main() {
- err := termui.Init()
- if err != nil {
- panic(err)
- }
- defer termui.Close()
-
- termui.UseTheme("helloworld")
-
- data := []int{4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6}
- spl0 := termui.NewSparkline()
- spl0.Data = data[3:]
- spl0.Title = "Sparkline 0"
- spl0.LineColor = termui.ColorGreen
-
- // single
- spls0 := termui.NewSparklines(spl0)
- spls0.Height = 2
- spls0.Width = 20
- spls0.HasBorder = false
-
- spl1 := termui.NewSparkline()
- spl1.Data = data
- spl1.Title = "Sparkline 1"
- spl1.LineColor = termui.ColorRed
-
- spl2 := termui.NewSparkline()
- spl2.Data = data[5:]
- spl2.Title = "Sparkline 2"
- spl2.LineColor = termui.ColorMagenta
-
- // group
- spls1 := termui.NewSparklines(spl0, spl1, spl2)
- spls1.Height = 8
- spls1.Width = 20
- spls1.Y = 3
- spls1.Border.Label = "Group Sparklines"
-
- spl3 := termui.NewSparkline()
- spl3.Data = data
- spl3.Title = "Enlarged Sparkline"
- spl3.Height = 8
- spl3.LineColor = termui.ColorYellow
-
- spls2 := termui.NewSparklines(spl3)
- spls2.Height = 11
- spls2.Width = 30
- spls2.Border.FgColor = termui.ColorCyan
- spls2.X = 21
- spls2.Border.Label = "Tweeked Sparkline"
-
- termui.Render(spls0, spls1, spls2)
-
- <-termui.EventCh()
-}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/sparklines.png b/Godeps/_workspace/src/github.com/gizak/termui/example/sparklines.png
deleted file mode 100644
index 9dd7c82b1..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/example/sparklines.png
+++ /dev/null
Binary files differ
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/theme.go b/Godeps/_workspace/src/github.com/gizak/termui/example/theme.go
deleted file mode 100644
index 30c51a343..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/example/theme.go
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
-// Use of this source code is governed by a MIT license that can
-// be found in the LICENSE file.
-
-// +build ignore
-
-package main
-
-import ui "github.com/gizak/termui"
-import "math"
-
-import "time"
-
-func main() {
- err := ui.Init()
- if err != nil {
- panic(err)
- }
- defer ui.Close()
-
- ui.UseTheme("helloworld")
-
- p := ui.NewPar(":PRESS q TO QUIT DEMO")
- p.Height = 3
- p.Width = 50
- p.Border.Label = "Text Box"
-
- strs := []string{"[0] gizak/termui", "[1] editbox.go", "[2] iterrupt.go", "[3] keyboard.go", "[4] output.go", "[5] random_out.go", "[6] dashboard.go", "[7] nsf/termbox-go"}
- list := ui.NewList()
- list.Items = strs
- list.Border.Label = "List"
- list.Height = 7
- list.Width = 25
- list.Y = 4
-
- g := ui.NewGauge()
- g.Percent = 50
- g.Width = 50
- g.Height = 3
- g.Y = 11
- g.Border.Label = "Gauge"
-
- spark := ui.NewSparkline()
- spark.Title = "srv 0:"
- spdata := []int{4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6}
- spark.Data = spdata
-
- spark1 := ui.NewSparkline()
- spark1.Title = "srv 1:"
- spark1.Data = spdata
-
- sp := ui.NewSparklines(spark, spark1)
- sp.Width = 25
- sp.Height = 7
- sp.Border.Label = "Sparkline"
- sp.Y = 4
- sp.X = 25
-
- lc := ui.NewLineChart()
- sinps := (func() []float64 {
- n := 100
- ps := make([]float64, n)
- for i := range ps {
- ps[i] = 1 + math.Sin(float64(i)/4)
- }
- return ps
- })()
-
- lc.Border.Label = "Line Chart"
- lc.Data = sinps
- lc.Width = 50
- lc.Height = 11
- lc.X = 0
- lc.Y = 14
- lc.Mode = "dot"
-
- bc := ui.NewBarChart()
- bcdata := []int{3, 2, 5, 3, 9, 5, 3, 2, 5, 8, 3, 2, 4, 5, 3, 2, 5, 7, 5, 3, 2, 6, 7, 4, 6, 3, 6, 7, 8, 3, 6, 4, 5, 3, 2, 4, 6, 4, 8, 5, 9, 4, 3, 6, 5, 3, 6}
- bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"}
- bc.Border.Label = "Bar Chart"
- bc.Width = 26
- bc.Height = 10
- bc.X = 51
- bc.Y = 0
- bc.DataLabels = bclabels
-
- lc1 := ui.NewLineChart()
- lc1.Border.Label = "Line Chart"
- rndwalk := (func() []float64 {
- n := 150
- d := make([]float64, n)
- for i := 1; i < n; i++ {
- if i < 20 {
- d[i] = d[i-1] + 0.01
- }
- if i > 20 {
- d[i] = d[i-1] - 0.05
- }
- }
- return d
- })()
- lc1.Data = rndwalk
- lc1.Width = 26
- lc1.Height = 11
- lc1.X = 51
- lc1.Y = 14
-
- p1 := ui.NewPar("Hey!\nI am a borderless block!")
- p1.HasBorder = false
- p1.Width = 26
- p1.Height = 2
- p1.X = 52
- p1.Y = 11
-
- draw := func(t int) {
- g.Percent = t % 101
- list.Items = strs[t%9:]
- sp.Lines[0].Data = spdata[t%10:]
- sp.Lines[1].Data = spdata[t/2%10:]
- lc.Data = sinps[t/2:]
- lc1.Data = rndwalk[t:]
- bc.Data = bcdata[t/2%10:]
- ui.Render(p, list, g, sp, lc, bc, lc1, p1)
- }
-
- evt := ui.EventCh()
- i := 0
- for {
- select {
- case e := <-evt:
- if e.Type == ui.EventKey && e.Ch == 'q' {
- return
- }
- default:
- draw(i)
- i++
- if i == 102 {
- return
- }
- time.Sleep(time.Second / 2)
- }
- }
-}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/themedefault.png b/Godeps/_workspace/src/github.com/gizak/termui/example/themedefault.png
deleted file mode 100644
index 23b574f96..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/example/themedefault.png
+++ /dev/null
Binary files differ
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/themehelloworld.png b/Godeps/_workspace/src/github.com/gizak/termui/example/themehelloworld.png
deleted file mode 100644
index eaf4d9303..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/example/themehelloworld.png
+++ /dev/null
Binary files differ
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/gauge.go b/Godeps/_workspace/src/github.com/gizak/termui/gauge.go
index 986f4f3dc..244d2995e 100644
--- a/Godeps/_workspace/src/github.com/gizak/termui/gauge.go
+++ b/Godeps/_workspace/src/github.com/gizak/termui/gauge.go
@@ -1,4 +1,4 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
+// Copyright 2016 Zack Guo <gizak@icloud.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
@@ -21,33 +21,27 @@ import (
g.PercentColor = termui.ColorBlue
*/
-// Align is the position of the gauge's label.
-type Align int
-
-// All supported positions.
-const (
- AlignLeft Align = iota
- AlignCenter
- AlignRight
-)
+const ColorUndef Attribute = Attribute(^uint16(0))
type Gauge struct {
Block
- Percent int
- BarColor Attribute
- PercentColor Attribute
- Label string
- LabelAlign Align
+ Percent int
+ BarColor Attribute
+ PercentColor Attribute
+ PercentColorHighlighted Attribute
+ Label string
+ LabelAlign Align
}
// NewGauge return a new gauge with current theme.
func NewGauge() *Gauge {
g := &Gauge{
- Block: *NewBlock(),
- PercentColor: theme.GaugePercent,
- BarColor: theme.GaugeBar,
- Label: "{{percent}}%",
- LabelAlign: AlignCenter,
+ Block: *NewBlock(),
+ PercentColor: ThemeAttr("gauge.percent.fg"),
+ BarColor: ThemeAttr("gauge.bar.bg"),
+ Label: "{{percent}}%",
+ LabelAlign: AlignCenter,
+ PercentColorHighlighted: ColorUndef,
}
g.Width = 12
@@ -56,28 +50,26 @@ func NewGauge() *Gauge {
}
// Buffer implements Bufferer interface.
-func (g *Gauge) Buffer() []Point {
- ps := g.Block.Buffer()
+func (g *Gauge) Buffer() Buffer {
+ buf := g.Block.Buffer()
// plot bar
- w := g.Percent * g.innerWidth / 100
- for i := 0; i < g.innerHeight; i++ {
+ w := g.Percent * g.innerArea.Dx() / 100
+ for i := 0; i < g.innerArea.Dy(); i++ {
for j := 0; j < w; j++ {
- p := Point{}
- p.X = g.innerX + j
- p.Y = g.innerY + i
- p.Ch = ' '
- p.Bg = g.BarColor
- if p.Bg == ColorDefault {
- p.Bg |= AttrReverse
+ c := Cell{}
+ c.Ch = ' '
+ c.Bg = g.BarColor
+ if c.Bg == ColorDefault {
+ c.Bg |= AttrReverse
}
- ps = append(ps, p)
+ buf.Set(g.innerArea.Min.X+j, g.innerArea.Min.Y+i, c)
}
}
// plot percentage
s := strings.Replace(g.Label, "{{percent}}", strconv.Itoa(g.Percent), -1)
- pry := g.innerY + g.innerHeight/2
+ pry := g.innerArea.Min.Y + g.innerArea.Dy()/2
rs := str2runes(s)
var pos int
switch g.LabelAlign {
@@ -85,29 +77,33 @@ func (g *Gauge) Buffer() []Point {
pos = 0
case AlignCenter:
- pos = (g.innerWidth - strWidth(s)) / 2
+ pos = (g.innerArea.Dx() - strWidth(s)) / 2
case AlignRight:
- pos = g.innerWidth - strWidth(s)
+ pos = g.innerArea.Dx() - strWidth(s) - 1
}
+ pos += g.innerArea.Min.X
for i, v := range rs {
- p := Point{}
- p.X = 1 + pos + i
- p.Y = pry
- p.Ch = v
- p.Fg = g.PercentColor
- if w+g.innerX > pos+i {
- p.Bg = g.BarColor
- if p.Bg == ColorDefault {
- p.Bg |= AttrReverse
+ c := Cell{
+ Ch: v,
+ Fg: g.PercentColor,
+ }
+
+ if w+g.innerArea.Min.X > pos+i {
+ c.Bg = g.BarColor
+ if c.Bg == ColorDefault {
+ c.Bg |= AttrReverse
}
+ if g.PercentColorHighlighted != ColorUndef {
+ c.Fg = g.PercentColorHighlighted
+ }
} else {
- p.Bg = g.Block.BgColor
+ c.Bg = g.Block.Bg
}
- ps = append(ps, p)
+ buf.Set(1+pos+i, pry, c)
}
- return g.Block.chopOverflow(ps)
+ return buf
}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/grid.go b/Godeps/_workspace/src/github.com/gizak/termui/grid.go
index 5f6e85e76..364442e02 100644
--- a/Godeps/_workspace/src/github.com/gizak/termui/grid.go
+++ b/Godeps/_workspace/src/github.com/gizak/termui/grid.go
@@ -1,4 +1,4 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
+// Copyright 2016 Zack Guo <gizak@icloud.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
@@ -160,8 +160,8 @@ func (r *Row) SetWidth(w int) {
// Buffer implements Bufferer interface,
// recursively merge all widgets buffer
-func (r *Row) Buffer() []Point {
- merged := []Point{}
+func (r *Row) Buffer() Buffer {
+ merged := NewBuffer()
if r.isRenderableLeaf() {
return r.Widget.Buffer()
@@ -169,13 +169,13 @@ func (r *Row) Buffer() []Point {
// for those are not leaves but have a renderable widget
if r.Widget != nil {
- merged = append(merged, r.Widget.Buffer()...)
+ merged.Merge(r.Widget.Buffer())
}
// collect buffer from children
if !r.isLeaf() {
for _, c := range r.Cols {
- merged = append(merged, c.Buffer()...)
+ merged.Merge(c.Buffer())
}
}
@@ -267,13 +267,13 @@ func (g *Grid) Align() {
}
// Buffer implments Bufferer interface.
-func (g Grid) Buffer() []Point {
- ps := []Point{}
+func (g Grid) Buffer() Buffer {
+ buf := NewBuffer()
+
for _, r := range g.Rows {
- ps = append(ps, r.Buffer()...)
+ buf.Merge(r.Buffer())
}
- return ps
+ return buf
}
-// Body corresponds to the entire terminal display region.
var Body *Grid
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/grid_test.go b/Godeps/_workspace/src/github.com/gizak/termui/grid_test.go
deleted file mode 100644
index cdafb2052..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/grid_test.go
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
-// Use of this source code is governed by a MIT license that can
-// be found in the LICENSE file.
-
-package termui
-
-import (
- "testing"
-
- "github.com/davecgh/go-spew/spew"
-)
-
-var r *Row
-
-func TestRowWidth(t *testing.T) {
- p0 := NewPar("p0")
- p0.Height = 1
- p1 := NewPar("p1")
- p1.Height = 1
- p2 := NewPar("p2")
- p2.Height = 1
- p3 := NewPar("p3")
- p3.Height = 1
-
- /* test against tree:
-
- r
- / \
- 0:w 1
- / \
- 10:w 11
- /
- 110:w
- /
- 1100:w
- */
- /*
- r = &row{
- Span: 12,
- Cols: []*row{
- &row{Widget: p0, Span: 6},
- &row{
- Span: 6,
- Cols: []*row{
- &row{Widget: p1, Span: 6},
- &row{
- Span: 6,
- Cols: []*row{
- &row{
- Span: 12,
- Widget: p2,
- Cols: []*row{
- &row{Span: 12, Widget: p3}}}}}}}}}
- */
-
- r = NewRow(
- NewCol(6, 0, p0),
- NewCol(6, 0,
- NewRow(
- NewCol(6, 0, p1),
- NewCol(6, 0, p2, p3))))
-
- r.assignWidth(100)
- if r.Width != 100 ||
- (r.Cols[0].Width) != 50 ||
- (r.Cols[1].Width) != 50 ||
- (r.Cols[1].Cols[0].Width) != 25 ||
- (r.Cols[1].Cols[1].Width) != 25 ||
- (r.Cols[1].Cols[1].Cols[0].Width) != 25 ||
- (r.Cols[1].Cols[1].Cols[0].Cols[0].Width) != 25 {
- t.Error("assignWidth fails")
- }
-}
-
-func TestRowHeight(t *testing.T) {
- spew.Dump()
-
- if (r.solveHeight()) != 2 ||
- (r.Cols[1].Cols[1].Height) != 2 ||
- (r.Cols[1].Cols[1].Cols[0].Height) != 2 ||
- (r.Cols[1].Cols[0].Height) != 1 {
- t.Error("solveHeight fails")
- }
-}
-
-func TestAssignXY(t *testing.T) {
- r.assignX(0)
- r.assignY(0)
- if (r.Cols[0].X) != 0 ||
- (r.Cols[1].Cols[0].X) != 50 ||
- (r.Cols[1].Cols[1].X) != 75 ||
- (r.Cols[1].Cols[1].Cols[0].X) != 75 ||
- (r.Cols[1].Cols[0].Y) != 0 ||
- (r.Cols[1].Cols[1].Cols[0].Y) != 0 ||
- (r.Cols[1].Cols[1].Cols[0].Cols[0].Y) != 1 {
- t.Error("assignXY fails")
- }
-}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/helper.go b/Godeps/_workspace/src/github.com/gizak/termui/helper.go
index 80d8a0278..6690e7fb0 100644
--- a/Godeps/_workspace/src/github.com/gizak/termui/helper.go
+++ b/Godeps/_workspace/src/github.com/gizak/termui/helper.go
@@ -1,10 +1,15 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
+// Copyright 2016 Zack Guo <gizak@icloud.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
package termui
-import tm "github.com/nsf/termbox-go"
+import (
+ "regexp"
+ "strings"
+
+ tm "github.com/nsf/termbox-go"
+)
import rw "github.com/mattn/go-runewidth"
/* ---------------Port from termbox-go --------------------- */
@@ -12,6 +17,7 @@ import rw "github.com/mattn/go-runewidth"
// Attribute is printable cell's color and style.
type Attribute uint16
+// 8 basic clolrs
const (
ColorDefault Attribute = iota
ColorBlack
@@ -24,7 +30,10 @@ const (
ColorWhite
)
-const NumberofColors = 8 //Have a constant that defines number of colors
+//Have a constant that defines number of colors
+const NumberofColors = 8
+
+// Text style
const (
AttrBold Attribute = 1 << (iota + 9)
AttrUnderline
@@ -46,15 +55,39 @@ func str2runes(s string) []rune {
return []rune(s)
}
+// Here for backwards-compatibility.
func trimStr2Runes(s string, w int) []rune {
+ return TrimStr2Runes(s, w)
+}
+
+// TrimStr2Runes trims string to w[-1 rune], appends …, and returns the runes
+// of that string if string is grather then n. If string is small then w,
+// return the runes.
+func TrimStr2Runes(s string, w int) []rune {
if w <= 0 {
return []rune{}
}
+
sw := rw.StringWidth(s)
if sw > w {
return []rune(rw.Truncate(s, w, dot))
}
- return str2runes(s) //[]rune(rw.Truncate(s, w, ""))
+ return str2runes(s)
+}
+
+// TrimStrIfAppropriate trim string to "s[:-1] + …"
+// if string > width otherwise return string
+func TrimStrIfAppropriate(s string, w int) string {
+ if w <= 0 {
+ return ""
+ }
+
+ sw := rw.StringWidth(s)
+ if sw > w {
+ return rw.Truncate(s, w, dot)
+ }
+
+ return s
}
func strWidth(s string) int {
@@ -64,3 +97,118 @@ func strWidth(s string) int {
func charWidth(ch rune) int {
return rw.RuneWidth(ch)
}
+
+var whiteSpaceRegex = regexp.MustCompile(`\s`)
+
+// StringToAttribute converts text to a termui attribute. You may specifiy more
+// then one attribute like that: "BLACK, BOLD, ...". All whitespaces
+// are ignored.
+func StringToAttribute(text string) Attribute {
+ text = whiteSpaceRegex.ReplaceAllString(strings.ToLower(text), "")
+ attributes := strings.Split(text, ",")
+ result := Attribute(0)
+
+ for _, theAttribute := range attributes {
+ var match Attribute
+ switch theAttribute {
+ case "reset", "default":
+ match = ColorDefault
+
+ case "black":
+ match = ColorBlack
+
+ case "red":
+ match = ColorRed
+
+ case "green":
+ match = ColorGreen
+
+ case "yellow":
+ match = ColorYellow
+
+ case "blue":
+ match = ColorBlue
+
+ case "magenta":
+ match = ColorMagenta
+
+ case "cyan":
+ match = ColorCyan
+
+ case "white":
+ match = ColorWhite
+
+ case "bold":
+ match = AttrBold
+
+ case "underline":
+ match = AttrUnderline
+
+ case "reverse":
+ match = AttrReverse
+ }
+
+ result |= match
+ }
+
+ return result
+}
+
+// TextCells returns a coloured text cells []Cell
+func TextCells(s string, fg, bg Attribute) []Cell {
+ cs := make([]Cell, 0, len(s))
+
+ // sequence := MarkdownTextRendererFactory{}.TextRenderer(s).Render(fg, bg)
+ // runes := []rune(sequence.NormalizedText)
+ runes := str2runes(s)
+
+ for n := range runes {
+ // point, _ := sequence.PointAt(n, 0, 0)
+ // cs = append(cs, Cell{point.Ch, point.Fg, point.Bg})
+ cs = append(cs, Cell{runes[n], fg, bg})
+ }
+ return cs
+}
+
+// Width returns the actual screen space the cell takes (usually 1 or 2).
+func (c Cell) Width() int {
+ return charWidth(c.Ch)
+}
+
+// Copy return a copy of c
+func (c Cell) Copy() Cell {
+ return c
+}
+
+// TrimTxCells trims the overflowed text cells sequence.
+func TrimTxCells(cs []Cell, w int) []Cell {
+ if len(cs) <= w {
+ return cs
+ }
+ return cs[:w]
+}
+
+// DTrimTxCls trims the overflowed text cells sequence and append dots at the end.
+func DTrimTxCls(cs []Cell, w int) []Cell {
+ l := len(cs)
+ if l <= 0 {
+ return []Cell{}
+ }
+
+ rt := make([]Cell, 0, w)
+ csw := 0
+ for i := 0; i < l && csw <= w; i++ {
+ c := cs[i]
+ cw := c.Width()
+
+ if cw+csw < w {
+ rt = append(rt, c)
+ csw += cw
+ } else {
+ rt = append(rt, Cell{'…', c.Fg, c.Bg})
+ break
+ }
+ }
+
+ return rt
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/helper_test.go b/Godeps/_workspace/src/github.com/gizak/termui/helper_test.go
deleted file mode 100644
index 6d1a56130..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/helper_test.go
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
-// Use of this source code is governed by a MIT license that can
-// be found in the LICENSE file.
-
-package termui
-
-import (
- "testing"
-
- "github.com/davecgh/go-spew/spew"
-)
-
-func TestStr2Rune(t *testing.T) {
- s := "你好,世界."
- rs := str2runes(s)
- if len(rs) != 6 {
- t.Error()
- }
-}
-
-func TestWidth(t *testing.T) {
- s0 := "つのだ☆HIRO"
- s1 := "11111111111"
- spew.Dump(s0)
- spew.Dump(s1)
- // above not align for setting East Asian Ambiguous to wide!!
-
- if strWidth(s0) != strWidth(s1) {
- t.Error("str len failed")
- }
-
- len1 := []rune{'a', '2', '&', '「', 'オ', '。'} //will false: 'ᆵ', 'ᄚ', 'ᄒ'
- for _, v := range len1 {
- if charWidth(v) != 1 {
- t.Error("len1 failed")
- }
- }
-
- len2 := []rune{'漢', '字', '한', '자', '你', '好', 'だ', '。', '%', 's', 'E', 'ョ', '、', 'ヲ'}
- for _, v := range len2 {
- if charWidth(v) != 2 {
- t.Error("len2 failed")
- }
- }
-}
-
-func TestTrim(t *testing.T) {
- s := "つのだ☆HIRO"
- if string(trimStr2Runes(s, 10)) != "つのだ☆HI"+dot {
- t.Error("trim failed")
- }
- if string(trimStr2Runes(s, 11)) != "つのだ☆HIRO" {
- t.Error("avoid tail trim failed")
- }
- if string(trimStr2Runes(s, 15)) != "つのだ☆HIRO" {
- t.Error("avoid trim failed")
- }
-}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/chart.go b/Godeps/_workspace/src/github.com/gizak/termui/linechart.go
index d6fb8bc7d..f2829148e 100644
--- a/Godeps/_workspace/src/github.com/gizak/termui/chart.go
+++ b/Godeps/_workspace/src/github.com/gizak/termui/linechart.go
@@ -1,4 +1,4 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
+// Copyright 2016 Zack Guo <gizak@icloud.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
@@ -74,8 +74,8 @@ type LineChart struct {
// NewLineChart returns a new LineChart with current theme.
func NewLineChart() *LineChart {
lc := &LineChart{Block: *NewBlock()}
- lc.AxesColor = theme.LineChartAxes
- lc.LineColor = theme.LineChartLine
+ lc.AxesColor = ThemeAttr("linechart.axes.fg")
+ lc.LineColor = ThemeAttr("linechart.line.fg")
lc.Mode = "braille"
lc.DotStyle = '•'
lc.axisXLebelGap = 2
@@ -87,8 +87,8 @@ func NewLineChart() *LineChart {
// one cell contains two data points
// so the capicity is 2x as dot-mode
-func (lc *LineChart) renderBraille() []Point {
- ps := []Point{}
+func (lc *LineChart) renderBraille() Buffer {
+ buf := NewBuffer()
// return: b -> which cell should the point be in
// m -> in the cell, divided into 4 equal height levels, which subcell?
@@ -104,44 +104,48 @@ func (lc *LineChart) renderBraille() []Point {
b1, m1 := getPos(lc.Data[2*i+1])
if b0 == b1 {
- p := Point{}
- p.Ch = braillePatterns[[2]int{m0, m1}]
- p.Bg = lc.BgColor
- p.Fg = lc.LineColor
- p.Y = lc.innerY + lc.innerHeight - 3 - b0
- p.X = lc.innerX + lc.labelYSpace + 1 + i
- ps = append(ps, p)
+ c := Cell{
+ Ch: braillePatterns[[2]int{m0, m1}],
+ Bg: lc.Bg,
+ Fg: lc.LineColor,
+ }
+ y := lc.innerArea.Min.Y + lc.innerArea.Dy() - 3 - b0
+ x := lc.innerArea.Min.X + lc.labelYSpace + 1 + i
+ buf.Set(x, y, c)
} else {
- p0 := newPointWithAttrs(lSingleBraille[m0],
- lc.innerX+lc.labelYSpace+1+i,
- lc.innerY+lc.innerHeight-3-b0,
- lc.LineColor,
- lc.BgColor)
- p1 := newPointWithAttrs(rSingleBraille[m1],
- lc.innerX+lc.labelYSpace+1+i,
- lc.innerY+lc.innerHeight-3-b1,
- lc.LineColor,
- lc.BgColor)
- ps = append(ps, p0, p1)
+ c0 := Cell{Ch: lSingleBraille[m0],
+ Fg: lc.LineColor,
+ Bg: lc.Bg}
+ x0 := lc.innerArea.Min.X + lc.labelYSpace + 1 + i
+ y0 := lc.innerArea.Min.Y + lc.innerArea.Dy() - 3 - b0
+ buf.Set(x0, y0, c0)
+
+ c1 := Cell{Ch: rSingleBraille[m1],
+ Fg: lc.LineColor,
+ Bg: lc.Bg}
+ x1 := lc.innerArea.Min.X + lc.labelYSpace + 1 + i
+ y1 := lc.innerArea.Min.Y + lc.innerArea.Dy() - 3 - b1
+ buf.Set(x1, y1, c1)
}
}
- return ps
+ return buf
}
-func (lc *LineChart) renderDot() []Point {
- ps := []Point{}
+func (lc *LineChart) renderDot() Buffer {
+ buf := NewBuffer()
for i := 0; i < len(lc.Data) && i < lc.axisXWidth; i++ {
- p := Point{}
- p.Ch = lc.DotStyle
- p.Fg = lc.LineColor
- p.Bg = lc.BgColor
- p.X = lc.innerX + lc.labelYSpace + 1 + i
- p.Y = lc.innerY + lc.innerHeight - 3 - int((lc.Data[i]-lc.bottomValue)/lc.scale+0.5)
- ps = append(ps, p)
+ c := Cell{
+ Ch: lc.DotStyle,
+ Fg: lc.LineColor,
+ Bg: lc.Bg,
+ }
+ x := lc.innerArea.Min.X + lc.labelYSpace + 1 + i
+ y := lc.innerArea.Min.Y + lc.innerArea.Dy() - 3 - int((lc.Data[i]-lc.bottomValue)/lc.scale+0.5)
+ buf.Set(x, y, c)
}
- return ps
+ return buf
}
func (lc *LineChart) calcLabelX() {
@@ -220,9 +224,9 @@ func (lc *LineChart) calcLayout() {
lc.maxY = lc.Data[0]
// valid visible range
- vrange := lc.innerWidth
+ vrange := lc.innerArea.Dx()
if lc.Mode == "braille" {
- vrange = 2 * lc.innerWidth
+ vrange = 2 * lc.innerArea.Dx()
}
if vrange > len(lc.Data) {
vrange = len(lc.Data)
@@ -247,40 +251,30 @@ func (lc *LineChart) calcLayout() {
lc.topValue = lc.maxY + 0.2*span
}
- lc.axisYHeight = lc.innerHeight - 2
+ lc.axisYHeight = lc.innerArea.Dy() - 2
lc.calcLabelY()
- lc.axisXWidth = lc.innerWidth - 1 - lc.labelYSpace
+ lc.axisXWidth = lc.innerArea.Dx() - 1 - lc.labelYSpace
lc.calcLabelX()
- lc.drawingX = lc.innerX + 1 + lc.labelYSpace
- lc.drawingY = lc.innerY
+ lc.drawingX = lc.innerArea.Min.X + 1 + lc.labelYSpace
+ lc.drawingY = lc.innerArea.Min.Y
}
-func (lc *LineChart) plotAxes() []Point {
- origY := lc.innerY + lc.innerHeight - 2
- origX := lc.innerX + lc.labelYSpace
+func (lc *LineChart) plotAxes() Buffer {
+ buf := NewBuffer()
+
+ origY := lc.innerArea.Min.Y + lc.innerArea.Dy() - 2
+ origX := lc.innerArea.Min.X + lc.labelYSpace
- ps := []Point{newPointWithAttrs(ORIGIN, origX, origY, lc.AxesColor, lc.BgColor)}
+ buf.Set(origX, origY, Cell{Ch: ORIGIN, Fg: lc.AxesColor, Bg: lc.Bg})
for x := origX + 1; x < origX+lc.axisXWidth; x++ {
- p := Point{}
- p.X = x
- p.Y = origY
- p.Bg = lc.BgColor
- p.Fg = lc.AxesColor
- p.Ch = HDASH
- ps = append(ps, p)
+ buf.Set(x, origY, Cell{Ch: HDASH, Fg: lc.AxesColor, Bg: lc.Bg})
}
for dy := 1; dy <= lc.axisYHeight; dy++ {
- p := Point{}
- p.X = origX
- p.Y = origY - dy
- p.Bg = lc.BgColor
- p.Fg = lc.AxesColor
- p.Ch = VDASH
- ps = append(ps, p)
+ buf.Set(origX, origY-dy, Cell{Ch: VDASH, Fg: lc.AxesColor, Bg: lc.Bg})
}
// x label
@@ -290,13 +284,14 @@ func (lc *LineChart) plotAxes() []Point {
break
}
for j, r := range rs {
- p := Point{}
- p.Ch = r
- p.Fg = lc.AxesColor
- p.Bg = lc.BgColor
- p.X = origX + oft + j
- p.Y = lc.innerY + lc.innerHeight - 1
- ps = append(ps, p)
+ c := Cell{
+ Ch: r,
+ Fg: lc.AxesColor,
+ Bg: lc.Bg,
+ }
+ x := origX + oft + j
+ y := lc.innerArea.Min.Y + lc.innerArea.Dy() - 1
+ buf.Set(x, y, c)
}
oft += len(rs) + lc.axisXLebelGap
}
@@ -304,33 +299,31 @@ func (lc *LineChart) plotAxes() []Point {
// y labels
for i, rs := range lc.labelY {
for j, r := range rs {
- p := Point{}
- p.Ch = r
- p.Fg = lc.AxesColor
- p.Bg = lc.BgColor
- p.X = lc.innerX + j
- p.Y = origY - i*(lc.axisYLebelGap+1)
- ps = append(ps, p)
+ buf.Set(
+ lc.innerArea.Min.X+j,
+ origY-i*(lc.axisYLebelGap+1),
+ Cell{Ch: r, Fg: lc.AxesColor, Bg: lc.Bg})
}
}
- return ps
+ return buf
}
// Buffer implements Bufferer interface.
-func (lc *LineChart) Buffer() []Point {
- ps := lc.Block.Buffer()
+func (lc *LineChart) Buffer() Buffer {
+ buf := lc.Block.Buffer()
+
if lc.Data == nil || len(lc.Data) == 0 {
- return ps
+ return buf
}
lc.calcLayout()
- ps = append(ps, lc.plotAxes()...)
+ buf.Merge(lc.plotAxes())
if lc.Mode == "dot" {
- ps = append(ps, lc.renderDot()...)
+ buf.Merge(lc.renderDot())
} else {
- ps = append(ps, lc.renderBraille()...)
+ buf.Merge(lc.renderBraille())
}
- return lc.Block.chopOverflow(ps)
+ return buf
}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/chart_others.go b/Godeps/_workspace/src/github.com/gizak/termui/linechart_others.go
index 8911873b6..7e2e66b3e 100644
--- a/Godeps/_workspace/src/github.com/gizak/termui/chart_others.go
+++ b/Godeps/_workspace/src/github.com/gizak/termui/linechart_others.go
@@ -1,4 +1,4 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
+// Copyright 2016 Zack Guo <gizak@icloud.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/chart_windows.go b/Godeps/_workspace/src/github.com/gizak/termui/linechart_windows.go
index 9f9a5e96c..1478b5ce3 100644
--- a/Godeps/_workspace/src/github.com/gizak/termui/chart_windows.go
+++ b/Godeps/_workspace/src/github.com/gizak/termui/linechart_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
+// Copyright 2016 Zack Guo <gizak@icloud.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/list.go b/Godeps/_workspace/src/github.com/gizak/termui/list.go
index 0640932f2..670015fd3 100644
--- a/Godeps/_workspace/src/github.com/gizak/termui/list.go
+++ b/Godeps/_workspace/src/github.com/gizak/termui/list.go
@@ -1,4 +1,4 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
+// Copyright 2016 Zack Guo <gizak@icloud.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
@@ -41,64 +41,49 @@ type List struct {
func NewList() *List {
l := &List{Block: *NewBlock()}
l.Overflow = "hidden"
- l.ItemFgColor = theme.ListItemFg
- l.ItemBgColor = theme.ListItemBg
+ l.ItemFgColor = ThemeAttr("list.item.fg")
+ l.ItemBgColor = ThemeAttr("list.item.bg")
return l
}
// Buffer implements Bufferer interface.
-func (l *List) Buffer() []Point {
- ps := l.Block.Buffer()
+func (l *List) Buffer() Buffer {
+ buf := l.Block.Buffer()
+
switch l.Overflow {
case "wrap":
- rs := str2runes(strings.Join(l.Items, "\n"))
+ cs := DefaultTxBuilder.Build(strings.Join(l.Items, "\n"), l.ItemFgColor, l.ItemBgColor)
i, j, k := 0, 0, 0
- for i < l.innerHeight && k < len(rs) {
- w := charWidth(rs[k])
- if rs[k] == '\n' || j+w > l.innerWidth {
+ for i < l.innerArea.Dy() && k < len(cs) {
+ w := cs[k].Width()
+ if cs[k].Ch == '\n' || j+w > l.innerArea.Dx() {
i++
j = 0
- if rs[k] == '\n' {
+ if cs[k].Ch == '\n' {
k++
}
continue
}
- pi := Point{}
- pi.X = l.innerX + j
- pi.Y = l.innerY + i
-
- pi.Ch = rs[k]
- pi.Bg = l.ItemBgColor
- pi.Fg = l.ItemFgColor
+ buf.Set(l.innerArea.Min.X+j, l.innerArea.Min.Y+i, cs[k])
- ps = append(ps, pi)
k++
j++
}
case "hidden":
trimItems := l.Items
- if len(trimItems) > l.innerHeight {
- trimItems = trimItems[:l.innerHeight]
+ if len(trimItems) > l.innerArea.Dy() {
+ trimItems = trimItems[:l.innerArea.Dy()]
}
for i, v := range trimItems {
- rs := trimStr2Runes(v, l.innerWidth)
-
+ cs := DTrimTxCls(DefaultTxBuilder.Build(v, l.ItemFgColor, l.ItemBgColor), l.innerArea.Dx())
j := 0
- for _, vv := range rs {
- w := charWidth(vv)
- p := Point{}
- p.X = l.innerX + j
- p.Y = l.innerY + i
-
- p.Ch = vv
- p.Bg = l.ItemBgColor
- p.Fg = l.ItemFgColor
-
- ps = append(ps, p)
+ for _, vv := range cs {
+ w := vv.Width()
+ buf.Set(l.innerArea.Min.X+j, l.innerArea.Min.Y+i, vv)
j += w
}
}
}
- return l.Block.chopOverflow(ps)
+ return buf
}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/mbar.go b/Godeps/_workspace/src/github.com/gizak/termui/mbarchart.go
index 9d18c2cb4..231de277f 100644
--- a/Godeps/_workspace/src/github.com/gizak/termui/mbar.go
+++ b/Godeps/_workspace/src/github.com/gizak/termui/mbarchart.go
@@ -1,4 +1,4 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
+// Copyright 2016 Zack Guo <gizak@icloud.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
@@ -48,16 +48,16 @@ type MBarChart struct {
// NewBarChart returns a new *BarChart with current theme.
func NewMBarChart() *MBarChart {
bc := &MBarChart{Block: *NewBlock()}
- bc.BarColor[0] = theme.MBarChartBar
- bc.NumColor[0] = theme.MBarChartNum
- bc.TextColor = theme.MBarChartText
+ bc.BarColor[0] = ThemeAttr("mbarchart.bar.bg")
+ bc.NumColor[0] = ThemeAttr("mbarchart.num.fg")
+ bc.TextColor = ThemeAttr("mbarchart.text.fg")
bc.BarGap = 1
bc.BarWidth = 3
return bc
}
func (bc *MBarChart) layout() {
- bc.numBar = bc.innerWidth / (bc.BarGap + bc.BarWidth)
+ bc.numBar = bc.innerArea.Dx() / (bc.BarGap + bc.BarWidth)
bc.labels = make([][]rune, bc.numBar)
DataLen := 0
LabelLen := len(bc.DataLabels)
@@ -129,9 +129,9 @@ func (bc *MBarChart) layout() {
if bc.ShowScale {
s := fmt.Sprintf("%d", bc.max)
bc.maxScale = trimStr2Runes(s, len(s))
- bc.scale = float64(bc.max) / float64(bc.innerHeight-2)
+ bc.scale = float64(bc.max) / float64(bc.innerArea.Dy()-2)
} else {
- bc.scale = float64(bc.max) / float64(bc.innerHeight-1)
+ bc.scale = float64(bc.max) / float64(bc.innerArea.Dy()-1)
}
}
@@ -144,8 +144,8 @@ func (bc *MBarChart) SetMax(max int) {
}
// Buffer implements Bufferer interface.
-func (bc *MBarChart) Buffer() []Point {
- ps := bc.Block.Buffer()
+func (bc *MBarChart) Buffer() Buffer {
+ buf := bc.Block.Buffer()
bc.layout()
var oftX int
@@ -157,15 +157,17 @@ func (bc *MBarChart) Buffer() []Point {
// plot bars
for j := 0; j < bc.BarWidth; j++ {
for k := 0; k < h; k++ {
- p := Point{}
- p.Ch = ' '
- p.Bg = bc.BarColor[i1]
+ c := Cell{
+ Ch: ' ',
+ Bg: bc.BarColor[i1],
+ }
if bc.BarColor[i1] == ColorDefault { // when color is default, space char treated as transparent!
- p.Bg |= AttrReverse
+ c.Bg |= AttrReverse
}
- p.X = bc.innerX + i*(bc.BarWidth+bc.BarGap) + j
- p.Y = bc.innerY + bc.innerHeight - 2 - k - ph
- ps = append(ps, p)
+ x := bc.innerArea.Min.X + i*(bc.BarWidth+bc.BarGap) + j
+ y := bc.innerArea.Min.Y + bc.innerArea.Dy() - 2 - k - ph
+ buf.Set(x, y, c)
+
}
}
ph += h
@@ -173,13 +175,14 @@ func (bc *MBarChart) Buffer() []Point {
// plot text
for j, k := 0, 0; j < len(bc.labels[i]); j++ {
w := charWidth(bc.labels[i][j])
- p := Point{}
- p.Ch = bc.labels[i][j]
- p.Bg = bc.BgColor
- p.Fg = bc.TextColor
- p.Y = bc.innerY + bc.innerHeight - 1
- p.X = bc.innerX + oftX + ((bc.BarWidth - len(bc.labels[i])) / 2) + k
- ps = append(ps, p)
+ c := Cell{
+ Ch: bc.labels[i][j],
+ Bg: bc.Bg,
+ Fg: bc.TextColor,
+ }
+ y := bc.innerArea.Min.Y + bc.innerArea.Dy() - 1
+ x := bc.innerArea.Max.X + oftX + ((bc.BarWidth - len(bc.labels[i])) / 2) + k
+ buf.Set(x, y, c)
k += w
}
// plot num
@@ -187,19 +190,20 @@ func (bc *MBarChart) Buffer() []Point {
for i1 := 0; i1 < bc.numStack; i1++ {
h := int(float64(bc.Data[i1][i]) / bc.scale)
for j := 0; j < len(bc.dataNum[i1][i]) && h > 0; j++ {
- p := Point{}
- p.Ch = bc.dataNum[i1][i][j]
- p.Fg = bc.NumColor[i1]
- p.Bg = bc.BarColor[i1]
+ c := Cell{
+ Ch: bc.dataNum[i1][i][j],
+ Fg: bc.NumColor[i1],
+ Bg: bc.BarColor[i1],
+ }
if bc.BarColor[i1] == ColorDefault { // the same as above
- p.Bg |= AttrReverse
+ c.Bg |= AttrReverse
}
if h == 0 {
- p.Bg = bc.BgColor
+ c.Bg = bc.Bg
}
- p.X = bc.innerX + oftX + (bc.BarWidth-len(bc.dataNum[i1][i]))/2 + j
- p.Y = bc.innerY + bc.innerHeight - 2 - ph
- ps = append(ps, p)
+ x := bc.innerArea.Min.X + oftX + (bc.BarWidth-len(bc.dataNum[i1][i]))/2 + j
+ y := bc.innerArea.Min.Y + bc.innerArea.Dy() - 2 - ph
+ buf.Set(x, y, c)
}
ph += h
}
@@ -208,26 +212,31 @@ func (bc *MBarChart) Buffer() []Point {
if bc.ShowScale {
//Currently bar graph only supprts data range from 0 to MAX
//Plot 0
- p := Point{}
- p.Ch = '0'
- p.Bg = bc.BgColor
- p.Fg = bc.TextColor
- p.Y = bc.innerY + bc.innerHeight - 2
- p.X = bc.X
- ps = append(ps, p)
+ c := Cell{
+ Ch: '0',
+ Bg: bc.Bg,
+ Fg: bc.TextColor,
+ }
+
+ y := bc.innerArea.Min.Y + bc.innerArea.Dy() - 2
+ x := bc.X
+ buf.Set(x, y, c)
//Plot the maximum sacle value
for i := 0; i < len(bc.maxScale); i++ {
- p := Point{}
- p.Ch = bc.maxScale[i]
- p.Bg = bc.BgColor
- p.Fg = bc.TextColor
- p.Y = bc.innerY
- p.X = bc.X + i
- ps = append(ps, p)
+ c := Cell{
+ Ch: bc.maxScale[i],
+ Bg: bc.Bg,
+ Fg: bc.TextColor,
+ }
+
+ y := bc.innerArea.Min.Y
+ x := bc.X + i
+
+ buf.Set(x, y, c)
}
}
- return bc.Block.chopOverflow(ps)
+ return buf
}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/p.go b/Godeps/_workspace/src/github.com/gizak/termui/p.go
deleted file mode 100644
index e327d7489..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/p.go
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
-// Use of this source code is governed by a MIT license that can
-// be found in the LICENSE file.
-
-package termui
-
-// Par displays a paragraph.
-/*
- par := termui.NewPar("Simple Text")
- par.Height = 3
- par.Width = 17
- par.Border.Label = "Label"
-*/
-type Par struct {
- Block
- Text string
- TextFgColor Attribute
- TextBgColor Attribute
-}
-
-// NewPar returns a new *Par with given text as its content.
-func NewPar(s string) *Par {
- return &Par{
- Block: *NewBlock(),
- Text: s,
- TextFgColor: theme.ParTextFg,
- TextBgColor: theme.ParTextBg}
-}
-
-// Buffer implements Bufferer interface.
-func (p *Par) Buffer() []Point {
- ps := p.Block.Buffer()
-
- rs := str2runes(p.Text)
- i, j, k := 0, 0, 0
- for i < p.innerHeight && k < len(rs) {
- // the width of char is about to print
- w := charWidth(rs[k])
-
- if rs[k] == '\n' || j+w > p.innerWidth {
- i++
- j = 0 // set x = 0
- if rs[k] == '\n' {
- k++
- }
-
- if i >= p.innerHeight {
- ps = append(ps, newPointWithAttrs('…',
- p.innerX+p.innerWidth-1,
- p.innerY+p.innerHeight-1,
- p.TextFgColor, p.TextBgColor))
- break
- }
-
- continue
- }
- pi := Point{}
- pi.X = p.innerX + j
- pi.Y = p.innerY + i
-
- pi.Ch = rs[k]
- pi.Bg = p.TextBgColor
- pi.Fg = p.TextFgColor
-
- ps = append(ps, pi)
-
- k++
- j += w
- }
- return p.Block.chopOverflow(ps)
-}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/par.go b/Godeps/_workspace/src/github.com/gizak/termui/par.go
new file mode 100644
index 000000000..c01bd0020
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/par.go
@@ -0,0 +1,64 @@
+// Copyright 2016 Zack Guo <gizak@icloud.com>. All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+package termui
+
+// Par displays a paragraph.
+/*
+ par := termui.NewPar("Simple Text")
+ par.Height = 3
+ par.Width = 17
+ par.Border.Label = "Label"
+*/
+type Par struct {
+ Block
+ Text string
+ TextFgColor Attribute
+ TextBgColor Attribute
+}
+
+// NewPar returns a new *Par with given text as its content.
+func NewPar(s string) *Par {
+ return &Par{
+ Block: *NewBlock(),
+ Text: s,
+ TextFgColor: ThemeAttr("par.text.fg"),
+ TextBgColor: ThemeAttr("par.text.bg"),
+ }
+}
+
+// Buffer implements Bufferer interface.
+func (p *Par) Buffer() Buffer {
+ buf := p.Block.Buffer()
+
+ fg, bg := p.TextFgColor, p.TextBgColor
+ cs := DefaultTxBuilder.Build(p.Text, fg, bg)
+
+ y, x, n := 0, 0, 0
+ for y < p.innerArea.Dy() && n < len(cs) {
+ w := cs[n].Width()
+ if cs[n].Ch == '\n' || x+w > p.innerArea.Dx() {
+ y++
+ x = 0 // set x = 0
+ if cs[n].Ch == '\n' {
+ n++
+ }
+
+ if y >= p.innerArea.Dy() {
+ buf.Set(p.innerArea.Min.X+p.innerArea.Dx()-1,
+ p.innerArea.Min.Y+p.innerArea.Dy()-1,
+ Cell{Ch: '…', Fg: p.TextFgColor, Bg: p.TextBgColor})
+ break
+ }
+ continue
+ }
+
+ buf.Set(p.innerArea.Min.X+x, p.innerArea.Min.Y+y, cs[n])
+
+ n++
+ x += w
+ }
+
+ return buf
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/point.go b/Godeps/_workspace/src/github.com/gizak/termui/point.go
deleted file mode 100644
index c381af9a4..000000000
--- a/Godeps/_workspace/src/github.com/gizak/termui/point.go
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
-// Use of this source code is governed by a MIT license that can
-// be found in the LICENSE file.
-
-package termui
-
-// Point stands for a single cell in terminal.
-type Point struct {
- Ch rune
- Bg Attribute
- Fg Attribute
- X int
- Y int
-}
-
-func newPoint(c rune, x, y int) (p Point) {
- p.Ch = c
- p.X = x
- p.Y = y
- return
-}
-
-func newPointWithAttrs(c rune, x, y int, fg, bg Attribute) Point {
- p := newPoint(c, x, y)
- p.Bg = bg
- p.Fg = fg
- return p
-}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/pos.go b/Godeps/_workspace/src/github.com/gizak/termui/pos.go
new file mode 100644
index 000000000..2046dce5a
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/pos.go
@@ -0,0 +1,78 @@
+// Copyright 2016 Zack Guo <gizak@icloud.com>. All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+package termui
+
+import "image"
+
+// Align is the position of the gauge's label.
+type Align uint
+
+// All supported positions.
+const (
+ AlignNone Align = 0
+ AlignLeft Align = 1 << iota
+ AlignRight
+ AlignBottom
+ AlignTop
+ AlignCenterVertical
+ AlignCenterHorizontal
+ AlignCenter = AlignCenterVertical | AlignCenterHorizontal
+)
+
+func AlignArea(parent, child image.Rectangle, a Align) image.Rectangle {
+ w, h := child.Dx(), child.Dy()
+
+ // parent center
+ pcx, pcy := parent.Min.X+parent.Dx()/2, parent.Min.Y+parent.Dy()/2
+ // child center
+ ccx, ccy := child.Min.X+child.Dx()/2, child.Min.Y+child.Dy()/2
+
+ if a&AlignLeft == AlignLeft {
+ child.Min.X = parent.Min.X
+ child.Max.X = child.Min.X + w
+ }
+
+ if a&AlignRight == AlignRight {
+ child.Max.X = parent.Max.X
+ child.Min.X = child.Max.X - w
+ }
+
+ if a&AlignBottom == AlignBottom {
+ child.Max.Y = parent.Max.Y
+ child.Min.Y = child.Max.Y - h
+ }
+
+ if a&AlignTop == AlignRight {
+ child.Min.Y = parent.Min.Y
+ child.Max.Y = child.Min.Y + h
+ }
+
+ if a&AlignCenterHorizontal == AlignCenterHorizontal {
+ child.Min.X += pcx - ccx
+ child.Max.X = child.Min.X + w
+ }
+
+ if a&AlignCenterVertical == AlignCenterVertical {
+ child.Min.Y += pcy - ccy
+ child.Max.Y = child.Min.Y + h
+ }
+
+ return child
+}
+
+func MoveArea(a image.Rectangle, dx, dy int) image.Rectangle {
+ a.Min.X += dx
+ a.Max.X += dx
+ a.Min.Y += dy
+ a.Max.Y += dy
+ return a
+}
+
+var termWidth int
+var termHeight int
+
+func TermRect() image.Rectangle {
+ return image.Rect(0, 0, termWidth, termHeight)
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/render.go b/Godeps/_workspace/src/github.com/gizak/termui/render.go
index d697d0aea..36544f063 100644
--- a/Godeps/_workspace/src/github.com/gizak/termui/render.go
+++ b/Godeps/_workspace/src/github.com/gizak/termui/render.go
@@ -1,29 +1,62 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
+// Copyright 2016 Zack Guo <gizak@icloud.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
package termui
-import tm "github.com/nsf/termbox-go"
+import (
+ "image"
+ "sync"
+ "time"
+
+ tm "github.com/nsf/termbox-go"
+)
// Bufferer should be implemented by all renderable components.
type Bufferer interface {
- Buffer() []Point
+ Buffer() Buffer
}
// Init initializes termui library. This function should be called before any others.
// After initialization, the library must be finalized by 'Close' function.
func Init() error {
+ if err := tm.Init(); err != nil {
+ return err
+ }
+
+ sysEvtChs = make([]chan Event, 0)
+ go hookTermboxEvt()
+
+ renderJobs = make(chan []Bufferer)
+ //renderLock = new(sync.RWMutex)
+
Body = NewGrid()
Body.X = 0
Body.Y = 0
- Body.BgColor = theme.BodyBg
- defer func() {
- w, _ := tm.Size()
- Body.Width = w
- evtListen()
+ Body.BgColor = ThemeAttr("bg")
+ Body.Width = TermWidth()
+
+ DefaultEvtStream.Init()
+ DefaultEvtStream.Merge("termbox", NewSysEvtCh())
+ DefaultEvtStream.Merge("timer", NewTimerCh(time.Second))
+ DefaultEvtStream.Merge("custom", usrEvtCh)
+
+ DefaultEvtStream.Handle("/", DefualtHandler)
+ DefaultEvtStream.Handle("/sys/wnd/resize", func(e Event) {
+ w := e.Data.(EvtWnd)
+ Body.Width = w.Width
+ })
+
+ DefaultWgtMgr = NewWgtMgr()
+ DefaultEvtStream.Hook(DefaultWgtMgr.WgtHandlersHook())
+
+ go func() {
+ for bs := range renderJobs {
+ render(bs...)
+ }
}()
- return tm.Init()
+
+ return nil
}
// Close finalizes termui library,
@@ -32,29 +65,71 @@ func Close() {
tm.Close()
}
+var renderLock sync.Mutex
+
+func termSync() {
+ renderLock.Lock()
+ tm.Sync()
+ termWidth, termHeight = tm.Size()
+ renderLock.Unlock()
+}
+
// TermWidth returns the current terminal's width.
func TermWidth() int {
- tm.Sync()
- w, _ := tm.Size()
- return w
+ termSync()
+ return termWidth
}
// TermHeight returns the current terminal's height.
func TermHeight() int {
- tm.Sync()
- _, h := tm.Size()
- return h
+ termSync()
+ return termHeight
}
// Render renders all Bufferer in the given order from left to right,
// right could overlap on left ones.
-func Render(rs ...Bufferer) {
- tm.Clear(tm.ColorDefault, toTmAttr(theme.BodyBg))
- for _, r := range rs {
- buf := r.Buffer()
- for _, v := range buf {
- tm.SetCell(v.X, v.Y, v.Ch, toTmAttr(v.Fg), toTmAttr(v.Bg))
+func render(bs ...Bufferer) {
+
+ for _, b := range bs {
+
+ buf := b.Buffer()
+ // set cels in buf
+ for p, c := range buf.CellMap {
+ if p.In(buf.Area) {
+
+ tm.SetCell(p.X, p.Y, c.Ch, toTmAttr(c.Fg), toTmAttr(c.Bg))
+
+ }
}
+
}
+
+ renderLock.Lock()
+ // render
tm.Flush()
+ renderLock.Unlock()
+}
+
+func Clear() {
+ tm.Clear(tm.ColorDefault, toTmAttr(ThemeAttr("bg")))
+}
+
+func clearArea(r image.Rectangle, bg Attribute) {
+ for i := r.Min.X; i < r.Max.X; i++ {
+ for j := r.Min.Y; j < r.Max.Y; j++ {
+ tm.SetCell(i, j, ' ', tm.ColorDefault, toTmAttr(bg))
+ }
+ }
+}
+
+func ClearArea(r image.Rectangle, bg Attribute) {
+ clearArea(r, bg)
+ tm.Flush()
+}
+
+var renderJobs chan []Bufferer
+
+func Render(bs ...Bufferer) {
+ //go func() { renderJobs <- bs }()
+ renderJobs <- bs
}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/sparkline.go b/Godeps/_workspace/src/github.com/gizak/termui/sparkline.go
index c63a5857f..312ad9563 100644
--- a/Godeps/_workspace/src/github.com/gizak/termui/sparkline.go
+++ b/Godeps/_workspace/src/github.com/gizak/termui/sparkline.go
@@ -1,12 +1,10 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
+// Copyright 2016 Zack Guo <gizak@icloud.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
package termui
-import "math"
-
-// Sparkline is like: ▅▆▂▂▅▇▂▂▃▆▆▆▅▃
+// Sparkline is like: ▅▆▂▂▅▇▂▂▃▆▆▆▅▃. The data points should be non-negative integers.
/*
data := []int{4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1}
spl := termui.NewSparkline()
@@ -49,8 +47,8 @@ func (s *Sparklines) Add(sl Sparkline) {
func NewSparkline() Sparkline {
return Sparkline{
Height: 1,
- TitleColor: theme.SparklineTitle,
- LineColor: theme.SparklineLine}
+ TitleColor: ThemeAttr("sparkline.title.fg"),
+ LineColor: ThemeAttr("sparkline.line.fg")}
}
// NewSparklines return a new *Spaklines with given Sparkline(s), you can always add a new Sparkline later.
@@ -67,13 +65,13 @@ func (sl *Sparklines) update() {
sl.Lines[i].displayHeight = v.Height + 1
}
}
- sl.displayWidth = sl.innerWidth
+ sl.displayWidth = sl.innerArea.Dx()
// get how many lines gotta display
h := 0
sl.displayLines = 0
for _, v := range sl.Lines {
- if h+v.displayHeight <= sl.innerHeight {
+ if h+v.displayHeight <= sl.innerArea.Dy() {
sl.displayLines++
} else {
break
@@ -84,20 +82,24 @@ func (sl *Sparklines) update() {
for i := 0; i < sl.displayLines; i++ {
data := sl.Lines[i].Data
- max := math.MinInt32
+ max := 0
for _, v := range data {
if max < v {
max = v
}
}
sl.Lines[i].max = max
- sl.Lines[i].scale = float32(8*sl.Lines[i].Height) / float32(max)
+ if max != 0 {
+ sl.Lines[i].scale = float32(8*sl.Lines[i].Height) / float32(max)
+ } else { // when all negative
+ sl.Lines[i].scale = 0
+ }
}
}
// Buffer implements Bufferer interface.
-func (sl *Sparklines) Buffer() []Point {
- ps := sl.Block.Buffer()
+func (sl *Sparklines) Buffer() Buffer {
+ buf := sl.Block.Buffer()
sl.update()
oftY := 0
@@ -105,52 +107,61 @@ func (sl *Sparklines) Buffer() []Point {
l := sl.Lines[i]
data := l.Data
- if len(data) > sl.innerWidth {
- data = data[len(data)-sl.innerWidth:]
+ if len(data) > sl.innerArea.Dx() {
+ data = data[len(data)-sl.innerArea.Dx():]
}
if l.Title != "" {
- rs := trimStr2Runes(l.Title, sl.innerWidth)
+ rs := trimStr2Runes(l.Title, sl.innerArea.Dx())
oftX := 0
for _, v := range rs {
w := charWidth(v)
- p := Point{}
- p.Ch = v
- p.Fg = l.TitleColor
- p.Bg = sl.BgColor
- p.X = sl.innerX + oftX
- p.Y = sl.innerY + oftY
- ps = append(ps, p)
+ c := Cell{
+ Ch: v,
+ Fg: l.TitleColor,
+ Bg: sl.Bg,
+ }
+ x := sl.innerArea.Min.X + oftX
+ y := sl.innerArea.Min.Y + oftY
+ buf.Set(x, y, c)
oftX += w
}
}
for j, v := range data {
+ // display height of the data point, zero when data is negative
h := int(float32(v)*l.scale + 0.5)
+ if v < 0 {
+ h = 0
+ }
+
barCnt := h / 8
barMod := h % 8
for jj := 0; jj < barCnt; jj++ {
- p := Point{}
- p.X = sl.innerX + j
- p.Y = sl.innerY + oftY + l.Height - jj
- p.Ch = ' ' // => sparks[7]
- p.Bg = l.LineColor
+ c := Cell{
+ Ch: ' ', // => sparks[7]
+ Bg: l.LineColor,
+ }
+ x := sl.innerArea.Min.X + j
+ y := sl.innerArea.Min.Y + oftY + l.Height - jj
+
//p.Bg = sl.BgColor
- ps = append(ps, p)
+ buf.Set(x, y, c)
}
if barMod != 0 {
- p := Point{}
- p.X = sl.innerX + j
- p.Y = sl.innerY + oftY + l.Height - barCnt
- p.Ch = sparks[barMod-1]
- p.Fg = l.LineColor
- p.Bg = sl.BgColor
- ps = append(ps, p)
+ c := Cell{
+ Ch: sparks[barMod-1],
+ Fg: l.LineColor,
+ Bg: sl.Bg,
+ }
+ x := sl.innerArea.Min.X + j
+ y := sl.innerArea.Min.Y + oftY + l.Height - barCnt
+ buf.Set(x, y, c)
}
}
oftY += l.displayHeight
}
- return sl.Block.chopOverflow(ps)
+ return buf
}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/test/runtest.go b/Godeps/_workspace/src/github.com/gizak/termui/test/runtest.go
new file mode 100644
index 000000000..99794c4db
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/test/runtest.go
@@ -0,0 +1,66 @@
+// Copyright 2016 Zack Guo <gizak@icloud.com>. All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/gizak/termui"
+ "github.com/gizak/termui/debug"
+)
+
+func main() {
+ // run as client
+ if len(os.Args) > 1 {
+ fmt.Print(debug.ConnectAndListen())
+ return
+ }
+
+ // run as server
+ go func() { panic(debug.ListenAndServe()) }()
+
+ if err := termui.Init(); err != nil {
+ panic(err)
+ }
+ defer termui.Close()
+
+ //termui.UseTheme("helloworld")
+ b := termui.NewBlock()
+ b.Width = 20
+ b.Height = 20
+ b.Float = termui.AlignCenter
+ b.BorderLabel = "[HELLO](fg-red,bg-white) [WORLD](fg-blue,bg-green)"
+
+ termui.Render(b)
+
+ termui.Handle("/sys", func(e termui.Event) {
+ k, ok := e.Data.(termui.EvtKbd)
+ debug.Logf("->%v\n", e)
+ if ok && k.KeyStr == "q" {
+ termui.StopLoop()
+ }
+ })
+
+ termui.Handle(("/usr"), func(e termui.Event) {
+ debug.Logf("->%v\n", e)
+ })
+
+ termui.Handle("/timer/1s", func(e termui.Event) {
+ t := e.Data.(termui.EvtTimer)
+ termui.SendCustomEvt("/usr/t", t.Count)
+
+ if t.Count%2 == 0 {
+ b.BorderLabel = "[HELLO](fg-red,bg-green) [WORLD](fg-blue,bg-white)"
+ } else {
+ b.BorderLabel = "[HELLO](fg-blue,bg-white) [WORLD](fg-red,bg-green)"
+ }
+
+ termui.Render(b)
+
+ })
+
+ termui.Loop()
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/textbuilder.go b/Godeps/_workspace/src/github.com/gizak/termui/textbuilder.go
new file mode 100644
index 000000000..6ff6d21f3
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/textbuilder.go
@@ -0,0 +1,215 @@
+// Copyright 2016 Zack Guo <gizak@icloud.com>. All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+package termui
+
+import (
+ "regexp"
+ "strings"
+)
+
+// TextBuilder is a minial interface to produce text []Cell using sepcific syntax (markdown).
+type TextBuilder interface {
+ Build(s string, fg, bg Attribute) []Cell
+}
+
+// DefaultTxBuilder is set to be MarkdownTxBuilder.
+var DefaultTxBuilder = NewMarkdownTxBuilder()
+
+// MarkdownTxBuilder implements TextBuilder interface, using markdown syntax.
+type MarkdownTxBuilder struct {
+ baseFg Attribute
+ baseBg Attribute
+ plainTx []rune
+ markers []marker
+}
+
+type marker struct {
+ st int
+ ed int
+ fg Attribute
+ bg Attribute
+}
+
+var colorMap = map[string]Attribute{
+ "red": ColorRed,
+ "blue": ColorBlue,
+ "black": ColorBlack,
+ "cyan": ColorCyan,
+ "yellow": ColorYellow,
+ "white": ColorWhite,
+ "default": ColorDefault,
+ "green": ColorGreen,
+ "magenta": ColorMagenta,
+}
+
+var attrMap = map[string]Attribute{
+ "bold": AttrBold,
+ "underline": AttrUnderline,
+ "reverse": AttrReverse,
+}
+
+func rmSpc(s string) string {
+ reg := regexp.MustCompile(`\s+`)
+ return reg.ReplaceAllString(s, "")
+}
+
+// readAttr translates strings like `fg-red,fg-bold,bg-white` to fg and bg Attribute
+func (mtb MarkdownTxBuilder) readAttr(s string) (Attribute, Attribute) {
+ fg := mtb.baseFg
+ bg := mtb.baseBg
+
+ updateAttr := func(a Attribute, attrs []string) Attribute {
+ for _, s := range attrs {
+ // replace the color
+ if c, ok := colorMap[s]; ok {
+ a &= 0xFF00 // erase clr 0 ~ 8 bits
+ a |= c // set clr
+ }
+ // add attrs
+ if c, ok := attrMap[s]; ok {
+ a |= c
+ }
+ }
+ return a
+ }
+
+ ss := strings.Split(s, ",")
+ fgs := []string{}
+ bgs := []string{}
+ for _, v := range ss {
+ subs := strings.Split(v, "-")
+ if len(subs) > 1 {
+ if subs[0] == "fg" {
+ fgs = append(fgs, subs[1])
+ }
+ if subs[0] == "bg" {
+ bgs = append(bgs, subs[1])
+ }
+ }
+ }
+
+ fg = updateAttr(fg, fgs)
+ bg = updateAttr(bg, bgs)
+ return fg, bg
+}
+
+func (mtb *MarkdownTxBuilder) reset() {
+ mtb.plainTx = []rune{}
+ mtb.markers = []marker{}
+}
+
+// parse streams and parses text into normalized text and render sequence.
+func (mtb *MarkdownTxBuilder) parse(str string) {
+ rs := str2runes(str)
+ normTx := []rune{}
+ square := []rune{}
+ brackt := []rune{}
+ accSquare := false
+ accBrackt := false
+ cntSquare := 0
+
+ reset := func() {
+ square = []rune{}
+ brackt = []rune{}
+ accSquare = false
+ accBrackt = false
+ cntSquare = 0
+ }
+ // pipe stacks into normTx and clear
+ rollback := func() {
+ normTx = append(normTx, square...)
+ normTx = append(normTx, brackt...)
+ reset()
+ }
+ // chop first and last
+ chop := func(s []rune) []rune {
+ return s[1 : len(s)-1]
+ }
+
+ for i, r := range rs {
+ switch {
+ // stacking brackt
+ case accBrackt:
+ brackt = append(brackt, r)
+ if ')' == r {
+ fg, bg := mtb.readAttr(string(chop(brackt)))
+ st := len(normTx)
+ ed := len(normTx) + len(square) - 2
+ mtb.markers = append(mtb.markers, marker{st, ed, fg, bg})
+ normTx = append(normTx, chop(square)...)
+ reset()
+ } else if i+1 == len(rs) {
+ rollback()
+ }
+ // stacking square
+ case accSquare:
+ switch {
+ // squares closed and followed by a '('
+ case cntSquare == 0 && '(' == r:
+ accBrackt = true
+ brackt = append(brackt, '(')
+ // squares closed but not followed by a '('
+ case cntSquare == 0:
+ rollback()
+ if '[' == r {
+ accSquare = true
+ cntSquare = 1
+ brackt = append(brackt, '[')
+ } else {
+ normTx = append(normTx, r)
+ }
+ // hit the end
+ case i+1 == len(rs):
+ square = append(square, r)
+ rollback()
+ case '[' == r:
+ cntSquare++
+ square = append(square, '[')
+ case ']' == r:
+ cntSquare--
+ square = append(square, ']')
+ // normal char
+ default:
+ square = append(square, r)
+ }
+ // stacking normTx
+ default:
+ if '[' == r {
+ accSquare = true
+ cntSquare = 1
+ square = append(square, '[')
+ } else {
+ normTx = append(normTx, r)
+ }
+ }
+ }
+
+ mtb.plainTx = normTx
+}
+
+// Build implements TextBuilder interface.
+func (mtb MarkdownTxBuilder) Build(s string, fg, bg Attribute) []Cell {
+ mtb.baseFg = fg
+ mtb.baseBg = bg
+ mtb.reset()
+ mtb.parse(s)
+ cs := make([]Cell, len(mtb.plainTx))
+ for i := range cs {
+ cs[i] = Cell{Ch: mtb.plainTx[i], Fg: fg, Bg: bg}
+ }
+ for _, mrk := range mtb.markers {
+ for i := mrk.st; i < mrk.ed; i++ {
+ cs[i].Fg = mrk.fg
+ cs[i].Bg = mrk.bg
+ }
+ }
+
+ return cs
+}
+
+// NewMarkdownTxBuilder returns a TextBuilder employing markdown syntax.
+func NewMarkdownTxBuilder() TextBuilder {
+ return MarkdownTxBuilder{}
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/theme.go b/Godeps/_workspace/src/github.com/gizak/termui/theme.go
index c8ad94756..c3ccda559 100644
--- a/Godeps/_workspace/src/github.com/gizak/termui/theme.go
+++ b/Godeps/_workspace/src/github.com/gizak/termui/theme.go
@@ -1,9 +1,12 @@
-// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
+// Copyright 2016 Zack Guo <gizak@icloud.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
package termui
+import "strings"
+
+/*
// A ColorScheme represents the current look-and-feel of the dashboard.
type ColorScheme struct {
BodyBg Attribute
@@ -29,6 +32,7 @@ type ColorScheme struct {
MBarChartBar Attribute
MBarChartText Attribute
MBarChartNum Attribute
+ TabActiveBg Attribute
}
// default color scheme depends on the user's terminal setting.
@@ -58,6 +62,7 @@ var themeHelloWorld = ColorScheme{
MBarChartBar: ColorRed,
MBarChartNum: ColorWhite,
MBarChartText: ColorCyan,
+ TabActiveBg: ColorMagenta,
}
var theme = themeDefault // global dep
@@ -82,3 +87,54 @@ func UseTheme(th string) {
theme = themeDefault
}
}
+*/
+
+var ColorMap = map[string]Attribute{
+ "fg": ColorWhite,
+ "bg": ColorDefault,
+ "border.fg": ColorWhite,
+ "label.fg": ColorGreen,
+ "par.fg": ColorYellow,
+ "par.label.bg": ColorWhite,
+}
+
+func ThemeAttr(name string) Attribute {
+ return lookUpAttr(ColorMap, name)
+}
+
+func lookUpAttr(clrmap map[string]Attribute, name string) Attribute {
+
+ a, ok := clrmap[name]
+ if ok {
+ return a
+ }
+
+ ns := strings.Split(name, ".")
+ for i := range ns {
+ nn := strings.Join(ns[i:len(ns)], ".")
+ a, ok = ColorMap[nn]
+ if ok {
+ break
+ }
+ }
+
+ return a
+}
+
+// 0<=r,g,b <= 5
+func ColorRGB(r, g, b int) Attribute {
+ within := func(n int) int {
+ if n < 0 {
+ return 0
+ }
+
+ if n > 5 {
+ return 5
+ }
+
+ return n
+ }
+
+ r, b, g = within(r), within(b), within(g)
+ return Attribute(0x0f + 36*r + 6*g + b)
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/widget.go b/Godeps/_workspace/src/github.com/gizak/termui/widget.go
new file mode 100644
index 000000000..35cf143a3
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/widget.go
@@ -0,0 +1,94 @@
+// Copyright 2016 Zack Guo <gizak@icloud.com>. All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+package termui
+
+import (
+ "fmt"
+ "sync"
+)
+
+// event mixins
+type WgtMgr map[string]WgtInfo
+
+type WgtInfo struct {
+ Handlers map[string]func(Event)
+ WgtRef Widget
+ Id string
+}
+
+type Widget interface {
+ Id() string
+}
+
+func NewWgtInfo(wgt Widget) WgtInfo {
+ return WgtInfo{
+ Handlers: make(map[string]func(Event)),
+ WgtRef: wgt,
+ Id: wgt.Id(),
+ }
+}
+
+func NewWgtMgr() WgtMgr {
+ wm := WgtMgr(make(map[string]WgtInfo))
+ return wm
+
+}
+
+func (wm WgtMgr) AddWgt(wgt Widget) {
+ wm[wgt.Id()] = NewWgtInfo(wgt)
+}
+
+func (wm WgtMgr) RmWgt(wgt Widget) {
+ wm.RmWgtById(wgt.Id())
+}
+
+func (wm WgtMgr) RmWgtById(id string) {
+ delete(wm, id)
+}
+
+func (wm WgtMgr) AddWgtHandler(id, path string, h func(Event)) {
+ if w, ok := wm[id]; ok {
+ w.Handlers[path] = h
+ }
+}
+
+func (wm WgtMgr) RmWgtHandler(id, path string) {
+ if w, ok := wm[id]; ok {
+ delete(w.Handlers, path)
+ }
+}
+
+var counter struct {
+ sync.RWMutex
+ count int
+}
+
+func GenId() string {
+ counter.Lock()
+ defer counter.Unlock()
+
+ counter.count += 1
+ return fmt.Sprintf("%d", counter.count)
+}
+
+func (wm WgtMgr) WgtHandlersHook() func(Event) {
+ return func(e Event) {
+ for _, v := range wm {
+ if k := findMatch(v.Handlers, e.Path); k != "" {
+ v.Handlers[k](e)
+ }
+ }
+ }
+}
+
+var DefaultWgtMgr WgtMgr
+
+func (b *Block) Handle(path string, handler func(Event)) {
+ if _, ok := DefaultWgtMgr[b.Id()]; !ok {
+ DefaultWgtMgr.AddWgt(b)
+ }
+
+ DefaultWgtMgr.AddWgtHandler(b.Id(), path, handler)
+}
diff --git a/Godeps/_workspace/src/github.com/golang/snappy/AUTHORS b/Godeps/_workspace/src/github.com/golang/snappy/AUTHORS
new file mode 100644
index 000000000..bcfa19520
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/golang/snappy/AUTHORS
@@ -0,0 +1,15 @@
+# This is the official list of Snappy-Go authors for copyright purposes.
+# This file is distinct from the CONTRIBUTORS files.
+# See the latter for an explanation.
+
+# Names should be added to this file as
+# Name or Organization <email address>
+# The email address is not required for organizations.
+
+# Please keep the list sorted.
+
+Damian Gryski <dgryski@gmail.com>
+Google Inc.
+Jan Mercl <0xjnml@gmail.com>
+Rodolfo Carvalho <rhcarvalho@gmail.com>
+Sebastien Binet <seb.binet@gmail.com>
diff --git a/Godeps/_workspace/src/github.com/golang/snappy/CONTRIBUTORS b/Godeps/_workspace/src/github.com/golang/snappy/CONTRIBUTORS
new file mode 100644
index 000000000..931ae3160
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/golang/snappy/CONTRIBUTORS
@@ -0,0 +1,37 @@
+# This is the official list of people who can contribute
+# (and typically have contributed) code to the Snappy-Go repository.
+# The AUTHORS file lists the copyright holders; this file
+# lists people. For example, Google employees are listed here
+# but not in AUTHORS, because Google holds the copyright.
+#
+# The submission process automatically checks to make sure
+# that people submitting code are listed in this file (by email address).
+#
+# Names should be added to this file only after verifying that
+# the individual or the individual's organization has agreed to
+# the appropriate Contributor License Agreement, found here:
+#
+# http://code.google.com/legal/individual-cla-v1.0.html
+# http://code.google.com/legal/corporate-cla-v1.0.html
+#
+# The agreement for individuals can be filled out on the web.
+#
+# When adding J Random Contributor's name to this file,
+# either J's name or J's organization's name should be
+# added to the AUTHORS file, depending on whether the
+# individual or corporate CLA was used.
+
+# Names should be added to this file like so:
+# Name <email address>
+
+# Please keep the list sorted.
+
+Damian Gryski <dgryski@gmail.com>
+Jan Mercl <0xjnml@gmail.com>
+Kai Backman <kaib@golang.org>
+Marc-Antoine Ruel <maruel@chromium.org>
+Nigel Tao <nigeltao@golang.org>
+Rob Pike <r@golang.org>
+Rodolfo Carvalho <rhcarvalho@gmail.com>
+Russ Cox <rsc@golang.org>
+Sebastien Binet <seb.binet@gmail.com>
diff --git a/Godeps/_workspace/src/github.com/golang/snappy/LICENSE b/Godeps/_workspace/src/github.com/golang/snappy/LICENSE
new file mode 100644
index 000000000..6050c10f4
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/golang/snappy/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2011 The Snappy-Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * 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.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+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
+OWNER 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.
diff --git a/Godeps/_workspace/src/github.com/golang/snappy/README b/Godeps/_workspace/src/github.com/golang/snappy/README
new file mode 100644
index 000000000..5074bbab8
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/golang/snappy/README
@@ -0,0 +1,7 @@
+The Snappy compression format in the Go programming language.
+
+To download and install from source:
+$ go get github.com/golang/snappy
+
+Unless otherwise noted, the Snappy-Go source files are distributed
+under the BSD-style license found in the LICENSE file.
diff --git a/Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/decode.go b/Godeps/_workspace/src/github.com/golang/snappy/decode.go
index 552a17bfb..8bab5bdd0 100644
--- a/Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/decode.go
+++ b/Godeps/_workspace/src/github.com/golang/snappy/decode.go
@@ -13,6 +13,8 @@ import (
var (
// ErrCorrupt reports that the input is invalid.
ErrCorrupt = errors.New("snappy: corrupt input")
+ // ErrTooLarge reports that the uncompressed length is too large.
+ ErrTooLarge = errors.New("snappy: decoded block is too large")
// ErrUnsupported reports that the input isn't supported.
ErrUnsupported = errors.New("snappy: unsupported input")
)
@@ -27,11 +29,13 @@ func DecodedLen(src []byte) (int, error) {
// that the length header occupied.
func decodedLen(src []byte) (blockLen, headerLen int, err error) {
v, n := binary.Uvarint(src)
- if n == 0 {
+ if n <= 0 || v > 0xffffffff {
return 0, 0, ErrCorrupt
}
- if uint64(int(v)) != v {
- return 0, 0, errors.New("snappy: decoded block is too large")
+
+ const wordSize = 32 << (^uint(0) >> 32 & 1)
+ if wordSize == 32 && v > 0x7fffffff {
+ return 0, 0, ErrTooLarge
}
return int(v), n, nil
}
@@ -56,7 +60,7 @@ func Decode(dst, src []byte) ([]byte, error) {
x := uint(src[s] >> 2)
switch {
case x < 60:
- s += 1
+ s++
case x == 60:
s += 2
if s > len(src) {
@@ -130,7 +134,7 @@ func Decode(dst, src []byte) ([]byte, error) {
// NewReader returns a new Reader that decompresses from r, using the framing
// format described at
-// https://code.google.com/p/snappy/source/browse/trunk/framing_format.txt
+// https://github.com/google/snappy/blob/master/framing_format.txt
func NewReader(r io.Reader) *Reader {
return &Reader{
r: r,
@@ -139,7 +143,7 @@ func NewReader(r io.Reader) *Reader {
}
}
-// Reader is an io.Reader than can read Snappy-compressed bytes.
+// Reader is an io.Reader that can read Snappy-compressed bytes.
type Reader struct {
r io.Reader
err error
@@ -200,7 +204,7 @@ func (r *Reader) Read(p []byte) (int, error) {
}
// The chunk types are specified at
- // https://code.google.com/p/snappy/source/browse/trunk/framing_format.txt
+ // https://github.com/google/snappy/blob/master/framing_format.txt
switch chunkType {
case chunkTypeCompressedData:
// Section 4.2. Compressed data (chunk type 0x00).
@@ -280,13 +284,11 @@ func (r *Reader) Read(p []byte) (int, error) {
// Section 4.5. Reserved unskippable chunks (chunk types 0x02-0x7f).
r.err = ErrUnsupported
return 0, r.err
-
- } else {
- // Section 4.4 Padding (chunk type 0xfe).
- // Section 4.6. Reserved skippable chunks (chunk types 0x80-0xfd).
- if !r.readFull(r.buf[:chunkLen]) {
- return 0, r.err
- }
+ }
+ // Section 4.4 Padding (chunk type 0xfe).
+ // Section 4.6. Reserved skippable chunks (chunk types 0x80-0xfd).
+ if !r.readFull(r.buf[:chunkLen]) {
+ return 0, r.err
}
}
}
diff --git a/Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/encode.go b/Godeps/_workspace/src/github.com/golang/snappy/encode.go
index dda372422..834e3b06a 100644
--- a/Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/encode.go
+++ b/Godeps/_workspace/src/github.com/golang/snappy/encode.go
@@ -6,6 +6,7 @@ package snappy
import (
"encoding/binary"
+ "errors"
"io"
)
@@ -79,7 +80,7 @@ func emitCopy(dst []byte, offset, length int) int {
// slice of dst if dst was large enough to hold the entire encoded block.
// Otherwise, a newly allocated slice will be returned.
// It is valid to pass a nil dst.
-func Encode(dst, src []byte) ([]byte, error) {
+func Encode(dst, src []byte) []byte {
if n := MaxEncodedLen(len(src)); len(dst) < n {
dst = make([]byte, n)
}
@@ -92,7 +93,7 @@ func Encode(dst, src []byte) ([]byte, error) {
if len(src) != 0 {
d += emitLiteral(dst[d:], src)
}
- return dst[:d], nil
+ return dst[:d]
}
// Initialize the hash table. Its size ranges from 1<<8 to 1<<14 inclusive.
@@ -122,7 +123,8 @@ func Encode(dst, src []byte) ([]byte, error) {
t, *p = *p-1, s+1
// If t is invalid or src[s:s+4] differs from src[t:t+4], accumulate a literal byte.
if t < 0 || s-t >= maxOffset || b0 != src[t] || b1 != src[t+1] || b2 != src[t+2] || b3 != src[t+3] {
- s++
+ // Skip multiple bytes if the last match was >= 32 bytes prior.
+ s += 1 + (s-lit)>>5
continue
}
// Otherwise, we have a match. First, emit any pending literal bytes.
@@ -145,7 +147,7 @@ func Encode(dst, src []byte) ([]byte, error) {
if lit != len(src) {
d += emitLiteral(dst[d:], src[lit:])
}
- return dst[:d], nil
+ return dst[:d]
}
// MaxEncodedLen returns the maximum length of a snappy block, given its
@@ -174,23 +176,56 @@ func MaxEncodedLen(srcLen int) int {
return 32 + srcLen + srcLen/6
}
-// NewWriter returns a new Writer that compresses to w, using the framing
-// format described at
-// https://code.google.com/p/snappy/source/browse/trunk/framing_format.txt
+var errClosed = errors.New("snappy: Writer is closed")
+
+// NewWriter returns a new Writer that compresses to w.
+//
+// The Writer returned does not buffer writes. There is no need to Flush or
+// Close such a Writer.
+//
+// Deprecated: the Writer returned is not suitable for many small writes, only
+// for few large writes. Use NewBufferedWriter instead, which is efficient
+// regardless of the frequency and shape of the writes, and remember to Close
+// that Writer when done.
func NewWriter(w io.Writer) *Writer {
return &Writer{
- w: w,
- enc: make([]byte, MaxEncodedLen(maxUncompressedChunkLen)),
+ w: w,
+ obuf: make([]byte, obufLen),
+ }
+}
+
+// NewBufferedWriter returns a new Writer that compresses to w, using the
+// framing format described at
+// https://github.com/google/snappy/blob/master/framing_format.txt
+//
+// The Writer returned buffers writes. Users must call Close to guarantee all
+// data has been forwarded to the underlying io.Writer. They may also call
+// Flush zero or more times before calling Close.
+func NewBufferedWriter(w io.Writer) *Writer {
+ return &Writer{
+ w: w,
+ ibuf: make([]byte, 0, maxUncompressedChunkLen),
+ obuf: make([]byte, obufLen),
}
}
// Writer is an io.Writer than can write Snappy-compressed bytes.
type Writer struct {
- w io.Writer
- err error
- enc []byte
- buf [checksumSize + chunkHeaderSize]byte
- wroteHeader bool
+ w io.Writer
+ err error
+
+ // ibuf is a buffer for the incoming (uncompressed) bytes.
+ //
+ // Its use is optional. For backwards compatibility, Writers created by the
+ // NewWriter function have ibuf == nil, do not buffer incoming bytes, and
+ // therefore do not need to be Flush'ed or Close'd.
+ ibuf []byte
+
+ // obuf is a buffer for the outgoing (compressed) bytes.
+ obuf []byte
+
+ // wroteStreamHeader is whether we have written the stream header.
+ wroteStreamHeader bool
}
// Reset discards the writer's state and switches the Snappy writer to write to
@@ -198,23 +233,60 @@ type Writer struct {
func (w *Writer) Reset(writer io.Writer) {
w.w = writer
w.err = nil
- w.wroteHeader = false
+ if w.ibuf != nil {
+ w.ibuf = w.ibuf[:0]
+ }
+ w.wroteStreamHeader = false
}
// Write satisfies the io.Writer interface.
-func (w *Writer) Write(p []byte) (n int, errRet error) {
- if w.err != nil {
- return 0, w.err
+func (w *Writer) Write(p []byte) (nRet int, errRet error) {
+ if w.ibuf == nil {
+ // Do not buffer incoming bytes. This does not perform or compress well
+ // if the caller of Writer.Write writes many small slices. This
+ // behavior is therefore deprecated, but still supported for backwards
+ // compatibility with code that doesn't explicitly Flush or Close.
+ return w.write(p)
}
- if !w.wroteHeader {
- copy(w.enc, magicChunk)
- if _, err := w.w.Write(w.enc[:len(magicChunk)]); err != nil {
- w.err = err
- return n, err
+
+ // The remainder of this method is based on bufio.Writer.Write from the
+ // standard library.
+
+ for len(p) > (cap(w.ibuf)-len(w.ibuf)) && w.err == nil {
+ var n int
+ if len(w.ibuf) == 0 {
+ // Large write, empty buffer.
+ // Write directly from p to avoid copy.
+ n, _ = w.write(p)
+ } else {
+ n = copy(w.ibuf[len(w.ibuf):cap(w.ibuf)], p)
+ w.ibuf = w.ibuf[:len(w.ibuf)+n]
+ w.Flush()
}
- w.wroteHeader = true
+ nRet += n
+ p = p[n:]
+ }
+ if w.err != nil {
+ return nRet, w.err
+ }
+ n := copy(w.ibuf[len(w.ibuf):cap(w.ibuf)], p)
+ w.ibuf = w.ibuf[:len(w.ibuf)+n]
+ nRet += n
+ return nRet, nil
+}
+
+func (w *Writer) write(p []byte) (nRet int, errRet error) {
+ if w.err != nil {
+ return 0, w.err
}
for len(p) > 0 {
+ obufStart := len(magicChunk)
+ if !w.wroteStreamHeader {
+ w.wroteStreamHeader = true
+ copy(w.obuf, magicChunk)
+ obufStart = 0
+ }
+
var uncompressed []byte
if len(p) > maxUncompressedChunkLen {
uncompressed, p = p[:maxUncompressedChunkLen], p[maxUncompressedChunkLen:]
@@ -225,34 +297,60 @@ func (w *Writer) Write(p []byte) (n int, errRet error) {
// Compress the buffer, discarding the result if the improvement
// isn't at least 12.5%.
+ compressed := Encode(w.obuf[obufHeaderLen:], uncompressed)
chunkType := uint8(chunkTypeCompressedData)
- chunkBody, err := Encode(w.enc, uncompressed)
- if err != nil {
- w.err = err
- return n, err
- }
- if len(chunkBody) >= len(uncompressed)-len(uncompressed)/8 {
- chunkType, chunkBody = chunkTypeUncompressedData, uncompressed
+ chunkLen := 4 + len(compressed)
+ obufEnd := obufHeaderLen + len(compressed)
+ if len(compressed) >= len(uncompressed)-len(uncompressed)/8 {
+ chunkType = chunkTypeUncompressedData
+ chunkLen = 4 + len(uncompressed)
+ obufEnd = obufHeaderLen
}
- chunkLen := 4 + len(chunkBody)
- w.buf[0] = chunkType
- w.buf[1] = uint8(chunkLen >> 0)
- w.buf[2] = uint8(chunkLen >> 8)
- w.buf[3] = uint8(chunkLen >> 16)
- w.buf[4] = uint8(checksum >> 0)
- w.buf[5] = uint8(checksum >> 8)
- w.buf[6] = uint8(checksum >> 16)
- w.buf[7] = uint8(checksum >> 24)
- if _, err = w.w.Write(w.buf[:]); err != nil {
+ // Fill in the per-chunk header that comes before the body.
+ w.obuf[len(magicChunk)+0] = chunkType
+ w.obuf[len(magicChunk)+1] = uint8(chunkLen >> 0)
+ w.obuf[len(magicChunk)+2] = uint8(chunkLen >> 8)
+ w.obuf[len(magicChunk)+3] = uint8(chunkLen >> 16)
+ w.obuf[len(magicChunk)+4] = uint8(checksum >> 0)
+ w.obuf[len(magicChunk)+5] = uint8(checksum >> 8)
+ w.obuf[len(magicChunk)+6] = uint8(checksum >> 16)
+ w.obuf[len(magicChunk)+7] = uint8(checksum >> 24)
+
+ if _, err := w.w.Write(w.obuf[obufStart:obufEnd]); err != nil {
w.err = err
- return n, err
+ return nRet, err
}
- if _, err = w.w.Write(chunkBody); err != nil {
- w.err = err
- return n, err
+ if chunkType == chunkTypeUncompressedData {
+ if _, err := w.w.Write(uncompressed); err != nil {
+ w.err = err
+ return nRet, err
+ }
}
- n += len(uncompressed)
+ nRet += len(uncompressed)
+ }
+ return nRet, nil
+}
+
+// Flush flushes the Writer to its underlying io.Writer.
+func (w *Writer) Flush() error {
+ if w.err != nil {
+ return w.err
+ }
+ if len(w.ibuf) == 0 {
+ return nil
+ }
+ w.write(w.ibuf)
+ w.ibuf = w.ibuf[:0]
+ return w.err
+}
+
+// Close calls Flush and then closes the Writer.
+func (w *Writer) Close() error {
+ w.Flush()
+ ret := w.err
+ if w.err == nil {
+ w.err = errClosed
}
- return n, nil
+ return ret
}
diff --git a/Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/snappy.go b/Godeps/_workspace/src/github.com/golang/snappy/snappy.go
index 043bf3d81..ef1e33e00 100644
--- a/Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/snappy.go
+++ b/Godeps/_workspace/src/github.com/golang/snappy/snappy.go
@@ -5,7 +5,7 @@
// Package snappy implements the snappy block-based compression format.
// It aims for very high speeds and reasonable compression.
//
-// The C++ snappy implementation is at http://code.google.com/p/snappy/
+// The C++ snappy implementation is at https://github.com/google/snappy
package snappy
import (
@@ -46,9 +46,18 @@ const (
chunkHeaderSize = 4
magicChunk = "\xff\x06\x00\x00" + magicBody
magicBody = "sNaPpY"
- // https://code.google.com/p/snappy/source/browse/trunk/framing_format.txt says
+ // https://github.com/google/snappy/blob/master/framing_format.txt says
// that "the uncompressed data in a chunk must be no longer than 65536 bytes".
maxUncompressedChunkLen = 65536
+
+ // maxEncodedLenOfMaxUncompressedChunkLen equals
+ // MaxEncodedLen(maxUncompressedChunkLen), but is hard coded to be a const
+ // instead of a variable, so that obufLen can also be a const. Their
+ // equivalence is confirmed by TestMaxEncodedLenOfMaxUncompressedChunkLen.
+ maxEncodedLenOfMaxUncompressedChunkLen = 76490
+
+ obufHeaderLen = len(magicChunk) + checksumSize + chunkHeaderSize
+ obufLen = obufHeaderLen + maxEncodedLenOfMaxUncompressedChunkLen
)
const (
@@ -61,7 +70,7 @@ const (
var crcTable = crc32.MakeTable(crc32.Castagnoli)
// crc implements the checksum specified in section 3 of
-// https://code.google.com/p/snappy/source/browse/trunk/framing_format.txt
+// https://github.com/google/snappy/blob/master/framing_format.txt
func crc(b []byte) uint32 {
c := crc32.Update(0, crcTable, b)
return uint32(c>>15|c<<17) + 0xa282ead8
diff --git a/Godeps/_workspace/src/github.com/hashicorp/golang-lru/2q.go b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/2q.go
new file mode 100644
index 000000000..337d96329
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/2q.go
@@ -0,0 +1,212 @@
+package lru
+
+import (
+ "fmt"
+ "sync"
+
+ "github.com/hashicorp/golang-lru/simplelru"
+)
+
+const (
+ // Default2QRecentRatio is the ratio of the 2Q cache dedicated
+ // to recently added entries that have only been accessed once.
+ Default2QRecentRatio = 0.25
+
+ // Default2QGhostEntries is the default ratio of ghost
+ // entries kept to track entries recently evicted
+ Default2QGhostEntries = 0.50
+)
+
+// TwoQueueCache is a thread-safe fixed size 2Q cache.
+// 2Q is an enhancement over the standard LRU cache
+// in that it tracks both frequently and recently used
+// entries separately. This avoids a burst in access to new
+// entries from evicting frequently used entries. It adds some
+// additional tracking overhead to the standard LRU cache, and is
+// computationally about 2x the cost, and adds some metadata over
+// head. The ARCCache is similar, but does not require setting any
+// parameters.
+type TwoQueueCache struct {
+ size int
+ recentSize int
+
+ recent *simplelru.LRU
+ frequent *simplelru.LRU
+ recentEvict *simplelru.LRU
+ lock sync.RWMutex
+}
+
+// New2Q creates a new TwoQueueCache using the default
+// values for the parameters.
+func New2Q(size int) (*TwoQueueCache, error) {
+ return New2QParams(size, Default2QRecentRatio, Default2QGhostEntries)
+}
+
+// New2QParams creates a new TwoQueueCache using the provided
+// parameter values.
+func New2QParams(size int, recentRatio float64, ghostRatio float64) (*TwoQueueCache, error) {
+ if size <= 0 {
+ return nil, fmt.Errorf("invalid size")
+ }
+ if recentRatio < 0.0 || recentRatio > 1.0 {
+ return nil, fmt.Errorf("invalid recent ratio")
+ }
+ if ghostRatio < 0.0 || ghostRatio > 1.0 {
+ return nil, fmt.Errorf("invalid ghost ratio")
+ }
+
+ // Determine the sub-sizes
+ recentSize := int(float64(size) * recentRatio)
+ evictSize := int(float64(size) * ghostRatio)
+
+ // Allocate the LRUs
+ recent, err := simplelru.NewLRU(size, nil)
+ if err != nil {
+ return nil, err
+ }
+ frequent, err := simplelru.NewLRU(size, nil)
+ if err != nil {
+ return nil, err
+ }
+ recentEvict, err := simplelru.NewLRU(evictSize, nil)
+ if err != nil {
+ return nil, err
+ }
+
+ // Initialize the cache
+ c := &TwoQueueCache{
+ size: size,
+ recentSize: recentSize,
+ recent: recent,
+ frequent: frequent,
+ recentEvict: recentEvict,
+ }
+ return c, nil
+}
+
+func (c *TwoQueueCache) Get(key interface{}) (interface{}, bool) {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ // Check if this is a frequent value
+ if val, ok := c.frequent.Get(key); ok {
+ return val, ok
+ }
+
+ // If the value is contained in recent, then we
+ // promote it to frequent
+ if val, ok := c.recent.Peek(key); ok {
+ c.recent.Remove(key)
+ c.frequent.Add(key, val)
+ return val, ok
+ }
+
+ // No hit
+ return nil, false
+}
+
+func (c *TwoQueueCache) Add(key, value interface{}) {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ // Check if the value is frequently used already,
+ // and just update the value
+ if c.frequent.Contains(key) {
+ c.frequent.Add(key, value)
+ return
+ }
+
+ // Check if the value is recently used, and promote
+ // the value into the frequent list
+ if c.recent.Contains(key) {
+ c.recent.Remove(key)
+ c.frequent.Add(key, value)
+ return
+ }
+
+ // If the value was recently evicted, add it to the
+ // frequently used list
+ if c.recentEvict.Contains(key) {
+ c.ensureSpace(true)
+ c.recentEvict.Remove(key)
+ c.frequent.Add(key, value)
+ return
+ }
+
+ // Add to the recently seen list
+ c.ensureSpace(false)
+ c.recent.Add(key, value)
+ return
+}
+
+// ensureSpace is used to ensure we have space in the cache
+func (c *TwoQueueCache) ensureSpace(recentEvict bool) {
+ // If we have space, nothing to do
+ recentLen := c.recent.Len()
+ freqLen := c.frequent.Len()
+ if recentLen+freqLen < c.size {
+ return
+ }
+
+ // If the recent buffer is larger than
+ // the target, evict from there
+ if recentLen > 0 && (recentLen > c.recentSize || (recentLen == c.recentSize && !recentEvict)) {
+ k, _, _ := c.recent.RemoveOldest()
+ c.recentEvict.Add(k, nil)
+ return
+ }
+
+ // Remove from the frequent list otherwise
+ c.frequent.RemoveOldest()
+}
+
+func (c *TwoQueueCache) Len() int {
+ c.lock.RLock()
+ defer c.lock.RUnlock()
+ return c.recent.Len() + c.frequent.Len()
+}
+
+func (c *TwoQueueCache) Keys() []interface{} {
+ c.lock.RLock()
+ defer c.lock.RUnlock()
+ k1 := c.frequent.Keys()
+ k2 := c.recent.Keys()
+ return append(k1, k2...)
+}
+
+func (c *TwoQueueCache) Remove(key interface{}) {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+ if c.frequent.Remove(key) {
+ return
+ }
+ if c.recent.Remove(key) {
+ return
+ }
+ if c.recentEvict.Remove(key) {
+ return
+ }
+}
+
+func (c *TwoQueueCache) Purge() {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+ c.recent.Purge()
+ c.frequent.Purge()
+ c.recentEvict.Purge()
+}
+
+func (c *TwoQueueCache) Contains(key interface{}) bool {
+ c.lock.RLock()
+ defer c.lock.RUnlock()
+ return c.frequent.Contains(key) || c.recent.Contains(key)
+}
+
+func (c *TwoQueueCache) Peek(key interface{}) (interface{}, bool) {
+ c.lock.RLock()
+ defer c.lock.RUnlock()
+ if val, ok := c.frequent.Peek(key); ok {
+ return val, ok
+ }
+ return c.recent.Peek(key)
+}
diff --git a/Godeps/_workspace/src/github.com/hashicorp/golang-lru/arc.go b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/arc.go
new file mode 100644
index 000000000..a2a252817
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/arc.go
@@ -0,0 +1,257 @@
+package lru
+
+import (
+ "sync"
+
+ "github.com/hashicorp/golang-lru/simplelru"
+)
+
+// ARCCache is a thread-safe fixed size Adaptive Replacement Cache (ARC).
+// ARC is an enhancement over the standard LRU cache in that tracks both
+// frequency and recency of use. This avoids a burst in access to new
+// entries from evicting the frequently used older entries. It adds some
+// additional tracking overhead to a standard LRU cache, computationally
+// it is roughly 2x the cost, and the extra memory overhead is linear
+// with the size of the cache. ARC has been patented by IBM, but is
+// similar to the TwoQueueCache (2Q) which requires setting parameters.
+type ARCCache struct {
+ size int // Size is the total capacity of the cache
+ p int // P is the dynamic preference towards T1 or T2
+
+ t1 *simplelru.LRU // T1 is the LRU for recently accessed items
+ b1 *simplelru.LRU // B1 is the LRU for evictions from t1
+
+ t2 *simplelru.LRU // T2 is the LRU for frequently accessed items
+ b2 *simplelru.LRU // B2 is the LRU for evictions from t2
+
+ lock sync.RWMutex
+}
+
+// NewARC creates an ARC of the given size
+func NewARC(size int) (*ARCCache, error) {
+ // Create the sub LRUs
+ b1, err := simplelru.NewLRU(size, nil)
+ if err != nil {
+ return nil, err
+ }
+ b2, err := simplelru.NewLRU(size, nil)
+ if err != nil {
+ return nil, err
+ }
+ t1, err := simplelru.NewLRU(size, nil)
+ if err != nil {
+ return nil, err
+ }
+ t2, err := simplelru.NewLRU(size, nil)
+ if err != nil {
+ return nil, err
+ }
+
+ // Initialize the ARC
+ c := &ARCCache{
+ size: size,
+ p: 0,
+ t1: t1,
+ b1: b1,
+ t2: t2,
+ b2: b2,
+ }
+ return c, nil
+}
+
+// Get looks up a key's value from the cache.
+func (c *ARCCache) Get(key interface{}) (interface{}, bool) {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ // Ff the value is contained in T1 (recent), then
+ // promote it to T2 (frequent)
+ if val, ok := c.t1.Peek(key); ok {
+ c.t1.Remove(key)
+ c.t2.Add(key, val)
+ return val, ok
+ }
+
+ // Check if the value is contained in T2 (frequent)
+ if val, ok := c.t2.Get(key); ok {
+ return val, ok
+ }
+
+ // No hit
+ return nil, false
+}
+
+// Add adds a value to the cache.
+func (c *ARCCache) Add(key, value interface{}) {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ // Check if the value is contained in T1 (recent), and potentially
+ // promote it to frequent T2
+ if c.t1.Contains(key) {
+ c.t1.Remove(key)
+ c.t2.Add(key, value)
+ return
+ }
+
+ // Check if the value is already in T2 (frequent) and update it
+ if c.t2.Contains(key) {
+ c.t2.Add(key, value)
+ return
+ }
+
+ // Check if this value was recently evicted as part of the
+ // recently used list
+ if c.b1.Contains(key) {
+ // T1 set is too small, increase P appropriately
+ delta := 1
+ b1Len := c.b1.Len()
+ b2Len := c.b2.Len()
+ if b2Len > b1Len {
+ delta = b2Len / b1Len
+ }
+ if c.p+delta >= c.size {
+ c.p = c.size
+ } else {
+ c.p += delta
+ }
+
+ // Potentially need to make room in the cache
+ if c.t1.Len()+c.t2.Len() >= c.size {
+ c.replace(false)
+ }
+
+ // Remove from B1
+ c.b1.Remove(key)
+
+ // Add the key to the frequently used list
+ c.t2.Add(key, value)
+ return
+ }
+
+ // Check if this value was recently evicted as part of the
+ // frequently used list
+ if c.b2.Contains(key) {
+ // T2 set is too small, decrease P appropriately
+ delta := 1
+ b1Len := c.b1.Len()
+ b2Len := c.b2.Len()
+ if b1Len > b2Len {
+ delta = b1Len / b2Len
+ }
+ if delta >= c.p {
+ c.p = 0
+ } else {
+ c.p -= delta
+ }
+
+ // Potentially need to make room in the cache
+ if c.t1.Len()+c.t2.Len() >= c.size {
+ c.replace(true)
+ }
+
+ // Remove from B2
+ c.b2.Remove(key)
+
+ // Add the key to the frequntly used list
+ c.t2.Add(key, value)
+ return
+ }
+
+ // Potentially need to make room in the cache
+ if c.t1.Len()+c.t2.Len() >= c.size {
+ c.replace(false)
+ }
+
+ // Keep the size of the ghost buffers trim
+ if c.b1.Len() > c.size-c.p {
+ c.b1.RemoveOldest()
+ }
+ if c.b2.Len() > c.p {
+ c.b2.RemoveOldest()
+ }
+
+ // Add to the recently seen list
+ c.t1.Add(key, value)
+ return
+}
+
+// replace is used to adaptively evict from either T1 or T2
+// based on the current learned value of P
+func (c *ARCCache) replace(b2ContainsKey bool) {
+ t1Len := c.t1.Len()
+ if t1Len > 0 && (t1Len > c.p || (t1Len == c.p && b2ContainsKey)) {
+ k, _, ok := c.t1.RemoveOldest()
+ if ok {
+ c.b1.Add(k, nil)
+ }
+ } else {
+ k, _, ok := c.t2.RemoveOldest()
+ if ok {
+ c.b2.Add(k, nil)
+ }
+ }
+}
+
+// Len returns the number of cached entries
+func (c *ARCCache) Len() int {
+ c.lock.RLock()
+ defer c.lock.RUnlock()
+ return c.t1.Len() + c.t2.Len()
+}
+
+// Keys returns all the cached keys
+func (c *ARCCache) Keys() []interface{} {
+ c.lock.RLock()
+ defer c.lock.RUnlock()
+ k1 := c.t1.Keys()
+ k2 := c.t2.Keys()
+ return append(k1, k2...)
+}
+
+// Remove is used to purge a key from the cache
+func (c *ARCCache) Remove(key interface{}) {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+ if c.t1.Remove(key) {
+ return
+ }
+ if c.t2.Remove(key) {
+ return
+ }
+ if c.b1.Remove(key) {
+ return
+ }
+ if c.b2.Remove(key) {
+ return
+ }
+}
+
+// Purge is used to clear the cache
+func (c *ARCCache) Purge() {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+ c.t1.Purge()
+ c.t2.Purge()
+ c.b1.Purge()
+ c.b2.Purge()
+}
+
+// Contains is used to check if the cache contains a key
+// without updating recency or frequency.
+func (c *ARCCache) Contains(key interface{}) bool {
+ c.lock.RLock()
+ defer c.lock.RUnlock()
+ return c.t1.Contains(key) || c.t2.Contains(key)
+}
+
+// Peek is used to inspect the cache value of a key
+// without updating recency or frequency.
+func (c *ARCCache) Peek(key interface{}) (interface{}, bool) {
+ c.lock.RLock()
+ defer c.lock.RUnlock()
+ if val, ok := c.t1.Peek(key); ok {
+ return val, ok
+ }
+ return c.t2.Peek(key)
+}
diff --git a/Godeps/_workspace/src/github.com/hashicorp/golang-lru/lru.go b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/lru.go
index 5f1e8a1af..a6285f989 100644
--- a/Godeps/_workspace/src/github.com/hashicorp/golang-lru/lru.go
+++ b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/lru.go
@@ -4,24 +4,15 @@
package lru
import (
- "container/list"
- "errors"
"sync"
+
+ "github.com/hashicorp/golang-lru/simplelru"
)
// Cache is a thread-safe fixed size LRU cache.
type Cache struct {
- size int
- evictList *list.List
- items map[interface{}]*list.Element
- lock sync.RWMutex
- onEvicted func(key interface{}, value interface{})
-}
-
-// entry is used to hold a value in the evictList
-type entry struct {
- key interface{}
- value interface{}
+ lru *simplelru.LRU
+ lock sync.RWMutex
}
// New creates an LRU of the given size
@@ -29,15 +20,15 @@ func New(size int) (*Cache, error) {
return NewWithEvict(size, nil)
}
+// NewWithEvict constructs a fixed size cache with the given eviction
+// callback.
func NewWithEvict(size int, onEvicted func(key interface{}, value interface{})) (*Cache, error) {
- if size <= 0 {
- return nil, errors.New("Must provide a positive size")
+ lru, err := simplelru.NewLRU(size, simplelru.EvictCallback(onEvicted))
+ if err != nil {
+ return nil, err
}
c := &Cache{
- size: size,
- evictList: list.New(),
- items: make(map[interface{}]*list.Element, size),
- onEvicted: onEvicted,
+ lru: lru,
}
return c, nil
}
@@ -45,131 +36,79 @@ func NewWithEvict(size int, onEvicted func(key interface{}, value interface{}))
// Purge is used to completely clear the cache
func (c *Cache) Purge() {
c.lock.Lock()
- defer c.lock.Unlock()
-
- if c.onEvicted != nil {
- for k, v := range c.items {
- c.onEvicted(k, v.Value.(*entry).value)
- }
- }
-
- c.evictList = list.New()
- c.items = make(map[interface{}]*list.Element, c.size)
+ c.lru.Purge()
+ c.lock.Unlock()
}
-// Add adds a value to the cache. Returns true if an eviction occured.
+// Add adds a value to the cache. Returns true if an eviction occurred.
func (c *Cache) Add(key, value interface{}) bool {
c.lock.Lock()
defer c.lock.Unlock()
-
- // Check for existing item
- if ent, ok := c.items[key]; ok {
- c.evictList.MoveToFront(ent)
- ent.Value.(*entry).value = value
- return false
- }
-
- // Add new item
- ent := &entry{key, value}
- entry := c.evictList.PushFront(ent)
- c.items[key] = entry
-
- evict := c.evictList.Len() > c.size
- // Verify size not exceeded
- if evict {
- c.removeOldest()
- }
- return evict
+ return c.lru.Add(key, value)
}
// Get looks up a key's value from the cache.
-func (c *Cache) Get(key interface{}) (value interface{}, ok bool) {
+func (c *Cache) Get(key interface{}) (interface{}, bool) {
c.lock.Lock()
defer c.lock.Unlock()
-
- if ent, ok := c.items[key]; ok {
- c.evictList.MoveToFront(ent)
- return ent.Value.(*entry).value, true
- }
- return
+ return c.lru.Get(key)
}
-// Check if a key is in the cache, without updating the recent-ness or deleting it for being stale.
-func (c *Cache) Contains(key interface{}) (ok bool) {
+// Check if a key is in the cache, without updating the recent-ness
+// or deleting it for being stale.
+func (c *Cache) Contains(key interface{}) bool {
c.lock.RLock()
defer c.lock.RUnlock()
-
- _, ok = c.items[key]
- return ok
+ return c.lru.Contains(key)
}
-// Returns the key value (or undefined if not found) without updating the "recently used"-ness of the key.
-// (If you find yourself using this a lot, you might be using the wrong sort of data structure, but there are some use cases where it's handy.)
-func (c *Cache) Peek(key interface{}) (value interface{}, ok bool) {
+// Returns the key value (or undefined if not found) without updating
+// the "recently used"-ness of the key.
+func (c *Cache) Peek(key interface{}) (interface{}, bool) {
c.lock.RLock()
defer c.lock.RUnlock()
+ return c.lru.Peek(key)
+}
- if ent, ok := c.items[key]; ok {
- return ent.Value.(*entry).value, true
+// ContainsOrAdd checks if a key is in the cache without updating the
+// recent-ness or deleting it for being stale, and if not, adds the value.
+// Returns whether found and whether an eviction occurred.
+func (c *Cache) ContainsOrAdd(key, value interface{}) (ok, evict bool) {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ if c.lru.Contains(key) {
+ return true, false
+ } else {
+ evict := c.lru.Add(key, value)
+ return false, evict
}
- return nil, ok
}
// Remove removes the provided key from the cache.
func (c *Cache) Remove(key interface{}) {
c.lock.Lock()
- defer c.lock.Unlock()
-
- if ent, ok := c.items[key]; ok {
- c.removeElement(ent)
- }
+ c.lru.Remove(key)
+ c.lock.Unlock()
}
// RemoveOldest removes the oldest item from the cache.
func (c *Cache) RemoveOldest() {
c.lock.Lock()
- defer c.lock.Unlock()
- c.removeOldest()
+ c.lru.RemoveOldest()
+ c.lock.Unlock()
}
// Keys returns a slice of the keys in the cache, from oldest to newest.
func (c *Cache) Keys() []interface{} {
c.lock.RLock()
defer c.lock.RUnlock()
-
- keys := make([]interface{}, len(c.items))
- ent := c.evictList.Back()
- i := 0
- for ent != nil {
- keys[i] = ent.Value.(*entry).key
- ent = ent.Prev()
- i++
- }
-
- return keys
+ return c.lru.Keys()
}
// Len returns the number of items in the cache.
func (c *Cache) Len() int {
c.lock.RLock()
defer c.lock.RUnlock()
- return c.evictList.Len()
-}
-
-// removeOldest removes the oldest item from the cache.
-func (c *Cache) removeOldest() {
- ent := c.evictList.Back()
- if ent != nil {
- c.removeElement(ent)
- }
-}
-
-// removeElement is used to remove a given list element from the cache
-func (c *Cache) removeElement(e *list.Element) {
- c.evictList.Remove(e)
- kv := e.Value.(*entry)
- delete(c.items, kv.key)
- if c.onEvicted != nil {
- c.onEvicted(kv.key, kv.value)
- }
+ return c.lru.Len()
}
diff --git a/Godeps/_workspace/src/github.com/hashicorp/golang-lru/lru_test.go b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/lru_test.go
deleted file mode 100644
index b676cfd9d..000000000
--- a/Godeps/_workspace/src/github.com/hashicorp/golang-lru/lru_test.go
+++ /dev/null
@@ -1,127 +0,0 @@
-package lru
-
-import "testing"
-
-func TestLRU(t *testing.T) {
- evictCounter := 0
- onEvicted := func(k interface{}, v interface{}) {
- if k != v {
- t.Fatalf("Evict values not equal (%v!=%v)", k, v)
- }
- evictCounter += 1
- }
- l, err := NewWithEvict(128, onEvicted)
- if err != nil {
- t.Fatalf("err: %v", err)
- }
-
- for i := 0; i < 256; i++ {
- l.Add(i, i)
- }
- if l.Len() != 128 {
- t.Fatalf("bad len: %v", l.Len())
- }
-
- if evictCounter != 128 {
- t.Fatalf("bad evict count: %v", evictCounter)
- }
-
- for i, k := range l.Keys() {
- if v, ok := l.Get(k); !ok || v != k || v != i+128 {
- t.Fatalf("bad key: %v", k)
- }
- }
- for i := 0; i < 128; i++ {
- _, ok := l.Get(i)
- if ok {
- t.Fatalf("should be evicted")
- }
- }
- for i := 128; i < 256; i++ {
- _, ok := l.Get(i)
- if !ok {
- t.Fatalf("should not be evicted")
- }
- }
- for i := 128; i < 192; i++ {
- l.Remove(i)
- _, ok := l.Get(i)
- if ok {
- t.Fatalf("should be deleted")
- }
- }
-
- l.Get(192) // expect 192 to be last key in l.Keys()
-
- for i, k := range l.Keys() {
- if (i < 63 && k != i+193) || (i == 63 && k != 192) {
- t.Fatalf("out of order key: %v", k)
- }
- }
-
- l.Purge()
- if l.Len() != 0 {
- t.Fatalf("bad len: %v", l.Len())
- }
- if _, ok := l.Get(200); ok {
- t.Fatalf("should contain nothing")
- }
-}
-
-// test that Add returns true/false if an eviction occured
-func TestLRUAdd(t *testing.T) {
- evictCounter := 0
- onEvicted := func(k interface{}, v interface{}) {
- evictCounter += 1
- }
-
- l, err := NewWithEvict(1, onEvicted)
- if err != nil {
- t.Fatalf("err: %v", err)
- }
-
- if l.Add(1, 1) == true || evictCounter != 0 {
- t.Errorf("should not have an eviction")
- }
- if l.Add(2, 2) == false || evictCounter != 1 {
- t.Errorf("should have an eviction")
- }
-}
-
-// test that Contains doesn't update recent-ness
-func TestLRUContains(t *testing.T) {
- l, err := New(2)
- if err != nil {
- t.Fatalf("err: %v", err)
- }
-
- l.Add(1, 1)
- l.Add(2, 2)
- if !l.Contains(1) {
- t.Errorf("1 should be contained")
- }
-
- l.Add(3, 3)
- if l.Contains(1) {
- t.Errorf("Contains should not have updated recent-ness of 1")
- }
-}
-
-// test that Peek doesn't update recent-ness
-func TestLRUPeek(t *testing.T) {
- l, err := New(2)
- if err != nil {
- t.Fatalf("err: %v", err)
- }
-
- l.Add(1, 1)
- l.Add(2, 2)
- if v, ok := l.Peek(1); !ok || v != 1 {
- t.Errorf("1 should be set to 1: %v, %v", v, ok)
- }
-
- l.Add(3, 3)
- if l.Contains(1) {
- t.Errorf("should not have updated recent-ness of 1")
- }
-}
diff --git a/Godeps/_workspace/src/github.com/hashicorp/golang-lru/simplelru/lru.go b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/simplelru/lru.go
new file mode 100644
index 000000000..68d097a1c
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/simplelru/lru.go
@@ -0,0 +1,160 @@
+package simplelru
+
+import (
+ "container/list"
+ "errors"
+)
+
+// EvictCallback is used to get a callback when a cache entry is evicted
+type EvictCallback func(key interface{}, value interface{})
+
+// LRU implements a non-thread safe fixed size LRU cache
+type LRU struct {
+ size int
+ evictList *list.List
+ items map[interface{}]*list.Element
+ onEvict EvictCallback
+}
+
+// entry is used to hold a value in the evictList
+type entry struct {
+ key interface{}
+ value interface{}
+}
+
+// NewLRU constructs an LRU of the given size
+func NewLRU(size int, onEvict EvictCallback) (*LRU, error) {
+ if size <= 0 {
+ return nil, errors.New("Must provide a positive size")
+ }
+ c := &LRU{
+ size: size,
+ evictList: list.New(),
+ items: make(map[interface{}]*list.Element),
+ onEvict: onEvict,
+ }
+ return c, nil
+}
+
+// Purge is used to completely clear the cache
+func (c *LRU) Purge() {
+ for k, v := range c.items {
+ if c.onEvict != nil {
+ c.onEvict(k, v.Value.(*entry).value)
+ }
+ delete(c.items, k)
+ }
+ c.evictList.Init()
+}
+
+// Add adds a value to the cache. Returns true if an eviction occured.
+func (c *LRU) Add(key, value interface{}) bool {
+ // Check for existing item
+ if ent, ok := c.items[key]; ok {
+ c.evictList.MoveToFront(ent)
+ ent.Value.(*entry).value = value
+ return false
+ }
+
+ // Add new item
+ ent := &entry{key, value}
+ entry := c.evictList.PushFront(ent)
+ c.items[key] = entry
+
+ evict := c.evictList.Len() > c.size
+ // Verify size not exceeded
+ if evict {
+ c.removeOldest()
+ }
+ return evict
+}
+
+// Get looks up a key's value from the cache.
+func (c *LRU) Get(key interface{}) (value interface{}, ok bool) {
+ if ent, ok := c.items[key]; ok {
+ c.evictList.MoveToFront(ent)
+ return ent.Value.(*entry).value, true
+ }
+ return
+}
+
+// Check if a key is in the cache, without updating the recent-ness
+// or deleting it for being stale.
+func (c *LRU) Contains(key interface{}) (ok bool) {
+ _, ok = c.items[key]
+ return ok
+}
+
+// Returns the key value (or undefined if not found) without updating
+// the "recently used"-ness of the key.
+func (c *LRU) Peek(key interface{}) (value interface{}, ok bool) {
+ if ent, ok := c.items[key]; ok {
+ return ent.Value.(*entry).value, true
+ }
+ return nil, ok
+}
+
+// Remove removes the provided key from the cache, returning if the
+// key was contained.
+func (c *LRU) Remove(key interface{}) bool {
+ if ent, ok := c.items[key]; ok {
+ c.removeElement(ent)
+ return true
+ }
+ return false
+}
+
+// RemoveOldest removes the oldest item from the cache.
+func (c *LRU) RemoveOldest() (interface{}, interface{}, bool) {
+ ent := c.evictList.Back()
+ if ent != nil {
+ c.removeElement(ent)
+ kv := ent.Value.(*entry)
+ return kv.key, kv.value, true
+ }
+ return nil, nil, false
+}
+
+// GetOldest returns the oldest entry
+func (c *LRU) GetOldest() (interface{}, interface{}, bool) {
+ ent := c.evictList.Back()
+ if ent != nil {
+ kv := ent.Value.(*entry)
+ return kv.key, kv.value, true
+ }
+ return nil, nil, false
+}
+
+// Keys returns a slice of the keys in the cache, from oldest to newest.
+func (c *LRU) Keys() []interface{} {
+ keys := make([]interface{}, len(c.items))
+ i := 0
+ for ent := c.evictList.Back(); ent != nil; ent = ent.Prev() {
+ keys[i] = ent.Value.(*entry).key
+ i++
+ }
+ return keys
+}
+
+// Len returns the number of items in the cache.
+func (c *LRU) Len() int {
+ return c.evictList.Len()
+}
+
+// removeOldest removes the oldest item from the cache.
+func (c *LRU) removeOldest() {
+ ent := c.evictList.Back()
+ if ent != nil {
+ c.removeElement(ent)
+ }
+}
+
+// removeElement is used to remove a given list element from the cache
+func (c *LRU) removeElement(e *list.Element) {
+ c.evictList.Remove(e)
+ kv := e.Value.(*entry)
+ delete(c.items, kv.key)
+ if c.onEvict != nil {
+ c.onEvict(kv.key, kv.value)
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/jackpal/gateway/LICENSE b/Godeps/_workspace/src/github.com/jackpal/gateway/LICENSE
new file mode 100644
index 000000000..c9efac32e
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/jackpal/gateway/LICENSE
@@ -0,0 +1,27 @@
+// Copyright (c) 2010 Jack Palevich. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// 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
+// OWNER 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.
diff --git a/Godeps/_workspace/src/github.com/jackpal/gateway/README.md b/Godeps/_workspace/src/github.com/jackpal/gateway/README.md
new file mode 100644
index 000000000..49cc0b85c
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/jackpal/gateway/README.md
@@ -0,0 +1,7 @@
+# gateway
+
+A very simple library for discovering the IP address of the local LAN gateway.
+
+Provides implementations for Linux, OS X (Darwin) and Windows.
+
+Pull requests for other OSs happily considered!
diff --git a/Godeps/_workspace/src/github.com/jackpal/gateway/gateway_darwin.go b/Godeps/_workspace/src/github.com/jackpal/gateway/gateway_darwin.go
new file mode 100644
index 000000000..fc6ef68d9
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/jackpal/gateway/gateway_darwin.go
@@ -0,0 +1,40 @@
+package gateway
+
+import (
+ "bytes"
+ "io/ioutil"
+ "net"
+ "os/exec"
+)
+
+func DiscoverGateway() (ip net.IP, err error) {
+ routeCmd := exec.Command("route", "-n", "get", "0.0.0.0")
+ stdOut, err := routeCmd.StdoutPipe()
+ if err != nil {
+ return
+ }
+ if err = routeCmd.Start(); err != nil {
+ return
+ }
+ output, err := ioutil.ReadAll(stdOut)
+ if err != nil {
+ return
+ }
+
+ // Darwin route out format is always like this:
+ // route to: default
+ // destination: default
+ // mask: default
+ // gateway: 192.168.1.1
+ outputLines := bytes.Split(output, []byte("\n"))
+ for _, line := range outputLines {
+ if bytes.Contains(line, []byte("gateway:")) {
+ gatewayFields := bytes.Fields(line)
+ ip = net.ParseIP(string(gatewayFields[1]))
+ break
+ }
+ }
+
+ err = routeCmd.Wait()
+ return
+}
diff --git a/Godeps/_workspace/src/github.com/jackpal/gateway/gateway_linux.go b/Godeps/_workspace/src/github.com/jackpal/gateway/gateway_linux.go
new file mode 100644
index 000000000..333bde1dc
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/jackpal/gateway/gateway_linux.go
@@ -0,0 +1,75 @@
+package gateway
+
+import (
+ "bytes"
+ "io/ioutil"
+ "net"
+ "os/exec"
+)
+
+func discoverGatewayUsingIp() (ip net.IP, err error) {
+ routeCmd := exec.Command("ip", "route", "show")
+ stdOut, err := routeCmd.StdoutPipe()
+ if err != nil {
+ return
+ }
+ if err = routeCmd.Start(); err != nil {
+ return
+ }
+ output, err := ioutil.ReadAll(stdOut)
+ if err != nil {
+ return
+ }
+
+ // Linux 'ip route show' format looks like this:
+ // default via 192.168.178.1 dev wlp3s0 metric 303
+ // 192.168.178.0/24 dev wlp3s0 proto kernel scope link src 192.168.178.76 metric 303
+ outputLines := bytes.Split(output, []byte("\n"))
+ for _, line := range outputLines {
+ if bytes.Contains(line, []byte("default")) {
+ ipFields := bytes.Fields(line)
+ ip = net.ParseIP(string(ipFields[2]))
+ break
+ }
+ }
+ err = routeCmd.Wait()
+ return
+}
+
+func discoverGatewayUsingRoute() (ip net.IP, err error) {
+ routeCmd := exec.Command("route", "-n")
+ stdOut, err := routeCmd.StdoutPipe()
+ if err != nil {
+ return
+ }
+ if err = routeCmd.Start(); err != nil {
+ return
+ }
+ output, err := ioutil.ReadAll(stdOut)
+ if err != nil {
+ return
+ }
+
+ // Linux route out format is always like this:
+ // Kernel IP routing table
+ // Destination Gateway Genmask Flags Metric Ref Use Iface
+ // 0.0.0.0 192.168.1.1 0.0.0.0 UG 0 0 0 eth0
+ outputLines := bytes.Split(output, []byte("\n"))
+ for _, line := range outputLines {
+ if bytes.Contains(line, []byte("0.0.0.0")) {
+ ipFields := bytes.Fields(line)
+ ip = net.ParseIP(string(ipFields[1]))
+ break
+ }
+ }
+ err = routeCmd.Wait()
+ return
+}
+
+func DiscoverGateway() (ip net.IP, err error) {
+ ip, err = discoverGatewayUsingRoute()
+ if err != nil {
+ ip, err = discoverGatewayUsingIp()
+ }
+ return
+}
diff --git a/Godeps/_workspace/src/github.com/jackpal/gateway/gateway_unimplemented.go b/Godeps/_workspace/src/github.com/jackpal/gateway/gateway_unimplemented.go
new file mode 100644
index 000000000..35042b910
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/jackpal/gateway/gateway_unimplemented.go
@@ -0,0 +1,14 @@
+// +build !darwin,!linux,!windows
+
+package gateway
+
+import (
+ "fmt"
+ "net"
+ "runtime"
+)
+
+func DiscoverGateway() (ip net.IP, err error) {
+ err = fmt.Errorf("DiscoverGateway not implemented for OS %s", runtime.GOOS)
+ return
+}
diff --git a/Godeps/_workspace/src/github.com/jackpal/gateway/gateway_windows.go b/Godeps/_workspace/src/github.com/jackpal/gateway/gateway_windows.go
new file mode 100644
index 000000000..282c8f685
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/jackpal/gateway/gateway_windows.go
@@ -0,0 +1,43 @@
+package gateway
+
+import (
+ "bytes"
+ "io/ioutil"
+ "net"
+ "os/exec"
+)
+
+func DiscoverGateway() (ip net.IP, err error) {
+ routeCmd := exec.Command("route", "print", "0.0.0.0")
+ stdOut, err := routeCmd.StdoutPipe()
+ if err != nil {
+ return
+ }
+ if err = routeCmd.Start(); err != nil {
+ return
+ }
+ output, err := ioutil.ReadAll(stdOut)
+ if err != nil {
+ return
+ }
+
+ // Windows route output format is always like this:
+ // ===========================================================================
+ // Active Routes:
+ // Network Destination Netmask Gateway Interface Metric
+ // 0.0.0.0 0.0.0.0 192.168.1.1 192.168.1.100 20
+ // ===========================================================================
+ // I'm trying to pick the active route,
+ // then jump 2 lines and pick the third IP
+ // Not using regex because output is quite standard from Windows XP to 8 (NEEDS TESTING)
+ outputLines := bytes.Split(output, []byte("\n"))
+ for idx, line := range outputLines {
+ if bytes.Contains(line, []byte("Active Routes:")) {
+ ipFields := bytes.Fields(outputLines[idx+2])
+ ip = net.ParseIP(string(ipFields[2]))
+ break
+ }
+ }
+ err = routeCmd.Wait()
+ return
+}
diff --git a/Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/natpmp.go b/Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/natpmp.go
index 8ce4e8342..7d9fb604e 100644
--- a/Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/natpmp.go
+++ b/Godeps/_workspace/src/github.com/jackpal/go-nat-pmp/natpmp.go
@@ -2,6 +2,7 @@ package natpmp
import (
"fmt"
+ "github.com/jackpal/gateway"
"log"
"net"
"time"
@@ -36,6 +37,17 @@ func NewClient(gateway net.IP) (nat *Client) {
return &Client{gateway}
}
+// Create a NAT-PMP client for the NAT-PMP server at the default gateway.
+func NewClientForDefaultGateway() (nat *Client, err error) {
+ var g net.IP
+ g, err = gateway.DiscoverGateway()
+ if err != nil {
+ return
+ }
+ nat = NewClient(g)
+ return
+}
+
// Results of the NAT-PMP GetExternalAddress operation
type GetExternalAddressResult struct {
SecondsSinceStartOfEpoc uint32
diff --git a/Godeps/_workspace/src/github.com/shiena/ansicolor/LICENSE b/Godeps/_workspace/src/github.com/mattn/go-colorable/LICENSE
index e58473ed9..91b5cef30 100644
--- a/Godeps/_workspace/src/github.com/shiena/ansicolor/LICENSE
+++ b/Godeps/_workspace/src/github.com/mattn/go-colorable/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) [2014] [shiena]
+Copyright (c) 2016 Yasuhiro Matsumoto
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/Godeps/_workspace/src/github.com/mattn/go-colorable/README.md b/Godeps/_workspace/src/github.com/mattn/go-colorable/README.md
new file mode 100644
index 000000000..e84226a73
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/mattn/go-colorable/README.md
@@ -0,0 +1,43 @@
+# go-colorable
+
+Colorable writer for windows.
+
+For example, most of logger packages doesn't show colors on windows. (I know we can do it with ansicon. But I don't want.)
+This package is possible to handle escape sequence for ansi color on windows.
+
+## Too Bad!
+
+![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/bad.png)
+
+
+## So Good!
+
+![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/good.png)
+
+## Usage
+
+```go
+logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true})
+logrus.SetOutput(colorable.NewColorableStdout())
+
+logrus.Info("succeeded")
+logrus.Warn("not correct")
+logrus.Error("something error")
+logrus.Fatal("panic")
+```
+
+You can compile above code on non-windows OSs.
+
+## Installation
+
+```
+$ go get github.com/mattn/go-colorable
+```
+
+# License
+
+MIT
+
+# Author
+
+Yasuhiro Matsumoto (a.k.a mattn)
diff --git a/Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_others.go b/Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_others.go
new file mode 100644
index 000000000..219f02f62
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_others.go
@@ -0,0 +1,16 @@
+// +build !windows
+
+package colorable
+
+import (
+ "io"
+ "os"
+)
+
+func NewColorableStdout() io.Writer {
+ return os.Stdout
+}
+
+func NewColorableStderr() io.Writer {
+ return os.Stderr
+}
diff --git a/Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_windows.go b/Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_windows.go
new file mode 100644
index 000000000..c551f7725
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_windows.go
@@ -0,0 +1,782 @@
+package colorable
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "math"
+ "os"
+ "strconv"
+ "strings"
+ "syscall"
+ "unsafe"
+
+ "github.com/mattn/go-isatty"
+)
+
+const (
+ foregroundBlue = 0x1
+ foregroundGreen = 0x2
+ foregroundRed = 0x4
+ foregroundIntensity = 0x8
+ foregroundMask = (foregroundRed | foregroundBlue | foregroundGreen | foregroundIntensity)
+ backgroundBlue = 0x10
+ backgroundGreen = 0x20
+ backgroundRed = 0x40
+ backgroundIntensity = 0x80
+ backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity)
+)
+
+type wchar uint16
+type short int16
+type dword uint32
+type word uint16
+
+type coord struct {
+ x short
+ y short
+}
+
+type smallRect struct {
+ left short
+ top short
+ right short
+ bottom short
+}
+
+type consoleScreenBufferInfo struct {
+ size coord
+ cursorPosition coord
+ attributes word
+ window smallRect
+ maximumWindowSize coord
+}
+
+var (
+ kernel32 = syscall.NewLazyDLL("kernel32.dll")
+ procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
+ procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute")
+ procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition")
+ procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
+ procFillConsoleOutputAttribute = kernel32.NewProc("FillConsoleOutputAttribute")
+)
+
+type Writer struct {
+ out io.Writer
+ handle syscall.Handle
+ lastbuf bytes.Buffer
+ oldattr word
+}
+
+func NewColorableStdout() io.Writer {
+ var csbi consoleScreenBufferInfo
+ out := os.Stdout
+ if !isatty.IsTerminal(out.Fd()) {
+ return out
+ }
+ handle := syscall.Handle(out.Fd())
+ procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
+ return &Writer{out: out, handle: handle, oldattr: csbi.attributes}
+}
+
+func NewColorableStderr() io.Writer {
+ var csbi consoleScreenBufferInfo
+ out := os.Stderr
+ if !isatty.IsTerminal(out.Fd()) {
+ return out
+ }
+ handle := syscall.Handle(out.Fd())
+ procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
+ return &Writer{out: out, handle: handle, oldattr: csbi.attributes}
+}
+
+var color256 = map[int]int{
+ 0: 0x000000,
+ 1: 0x800000,
+ 2: 0x008000,
+ 3: 0x808000,
+ 4: 0x000080,
+ 5: 0x800080,
+ 6: 0x008080,
+ 7: 0xc0c0c0,
+ 8: 0x808080,
+ 9: 0xff0000,
+ 10: 0x00ff00,
+ 11: 0xffff00,
+ 12: 0x0000ff,
+ 13: 0xff00ff,
+ 14: 0x00ffff,
+ 15: 0xffffff,
+ 16: 0x000000,
+ 17: 0x00005f,
+ 18: 0x000087,
+ 19: 0x0000af,
+ 20: 0x0000d7,
+ 21: 0x0000ff,
+ 22: 0x005f00,
+ 23: 0x005f5f,
+ 24: 0x005f87,
+ 25: 0x005faf,
+ 26: 0x005fd7,
+ 27: 0x005fff,
+ 28: 0x008700,
+ 29: 0x00875f,
+ 30: 0x008787,
+ 31: 0x0087af,
+ 32: 0x0087d7,
+ 33: 0x0087ff,
+ 34: 0x00af00,
+ 35: 0x00af5f,
+ 36: 0x00af87,
+ 37: 0x00afaf,
+ 38: 0x00afd7,
+ 39: 0x00afff,
+ 40: 0x00d700,
+ 41: 0x00d75f,
+ 42: 0x00d787,
+ 43: 0x00d7af,
+ 44: 0x00d7d7,
+ 45: 0x00d7ff,
+ 46: 0x00ff00,
+ 47: 0x00ff5f,
+ 48: 0x00ff87,
+ 49: 0x00ffaf,
+ 50: 0x00ffd7,
+ 51: 0x00ffff,
+ 52: 0x5f0000,
+ 53: 0x5f005f,
+ 54: 0x5f0087,
+ 55: 0x5f00af,
+ 56: 0x5f00d7,
+ 57: 0x5f00ff,
+ 58: 0x5f5f00,
+ 59: 0x5f5f5f,
+ 60: 0x5f5f87,
+ 61: 0x5f5faf,
+ 62: 0x5f5fd7,
+ 63: 0x5f5fff,
+ 64: 0x5f8700,
+ 65: 0x5f875f,
+ 66: 0x5f8787,
+ 67: 0x5f87af,
+ 68: 0x5f87d7,
+ 69: 0x5f87ff,
+ 70: 0x5faf00,
+ 71: 0x5faf5f,
+ 72: 0x5faf87,
+ 73: 0x5fafaf,
+ 74: 0x5fafd7,
+ 75: 0x5fafff,
+ 76: 0x5fd700,
+ 77: 0x5fd75f,
+ 78: 0x5fd787,
+ 79: 0x5fd7af,
+ 80: 0x5fd7d7,
+ 81: 0x5fd7ff,
+ 82: 0x5fff00,
+ 83: 0x5fff5f,
+ 84: 0x5fff87,
+ 85: 0x5fffaf,
+ 86: 0x5fffd7,
+ 87: 0x5fffff,
+ 88: 0x870000,
+ 89: 0x87005f,
+ 90: 0x870087,
+ 91: 0x8700af,
+ 92: 0x8700d7,
+ 93: 0x8700ff,
+ 94: 0x875f00,
+ 95: 0x875f5f,
+ 96: 0x875f87,
+ 97: 0x875faf,
+ 98: 0x875fd7,
+ 99: 0x875fff,
+ 100: 0x878700,
+ 101: 0x87875f,
+ 102: 0x878787,
+ 103: 0x8787af,
+ 104: 0x8787d7,
+ 105: 0x8787ff,
+ 106: 0x87af00,
+ 107: 0x87af5f,
+ 108: 0x87af87,
+ 109: 0x87afaf,
+ 110: 0x87afd7,
+ 111: 0x87afff,
+ 112: 0x87d700,
+ 113: 0x87d75f,
+ 114: 0x87d787,
+ 115: 0x87d7af,
+ 116: 0x87d7d7,
+ 117: 0x87d7ff,
+ 118: 0x87ff00,
+ 119: 0x87ff5f,
+ 120: 0x87ff87,
+ 121: 0x87ffaf,
+ 122: 0x87ffd7,
+ 123: 0x87ffff,
+ 124: 0xaf0000,
+ 125: 0xaf005f,
+ 126: 0xaf0087,
+ 127: 0xaf00af,
+ 128: 0xaf00d7,
+ 129: 0xaf00ff,
+ 130: 0xaf5f00,
+ 131: 0xaf5f5f,
+ 132: 0xaf5f87,
+ 133: 0xaf5faf,
+ 134: 0xaf5fd7,
+ 135: 0xaf5fff,
+ 136: 0xaf8700,
+ 137: 0xaf875f,
+ 138: 0xaf8787,
+ 139: 0xaf87af,
+ 140: 0xaf87d7,
+ 141: 0xaf87ff,
+ 142: 0xafaf00,
+ 143: 0xafaf5f,
+ 144: 0xafaf87,
+ 145: 0xafafaf,
+ 146: 0xafafd7,
+ 147: 0xafafff,
+ 148: 0xafd700,
+ 149: 0xafd75f,
+ 150: 0xafd787,
+ 151: 0xafd7af,
+ 152: 0xafd7d7,
+ 153: 0xafd7ff,
+ 154: 0xafff00,
+ 155: 0xafff5f,
+ 156: 0xafff87,
+ 157: 0xafffaf,
+ 158: 0xafffd7,
+ 159: 0xafffff,
+ 160: 0xd70000,
+ 161: 0xd7005f,
+ 162: 0xd70087,
+ 163: 0xd700af,
+ 164: 0xd700d7,
+ 165: 0xd700ff,
+ 166: 0xd75f00,
+ 167: 0xd75f5f,
+ 168: 0xd75f87,
+ 169: 0xd75faf,
+ 170: 0xd75fd7,
+ 171: 0xd75fff,
+ 172: 0xd78700,
+ 173: 0xd7875f,
+ 174: 0xd78787,
+ 175: 0xd787af,
+ 176: 0xd787d7,
+ 177: 0xd787ff,
+ 178: 0xd7af00,
+ 179: 0xd7af5f,
+ 180: 0xd7af87,
+ 181: 0xd7afaf,
+ 182: 0xd7afd7,
+ 183: 0xd7afff,
+ 184: 0xd7d700,
+ 185: 0xd7d75f,
+ 186: 0xd7d787,
+ 187: 0xd7d7af,
+ 188: 0xd7d7d7,
+ 189: 0xd7d7ff,
+ 190: 0xd7ff00,
+ 191: 0xd7ff5f,
+ 192: 0xd7ff87,
+ 193: 0xd7ffaf,
+ 194: 0xd7ffd7,
+ 195: 0xd7ffff,
+ 196: 0xff0000,
+ 197: 0xff005f,
+ 198: 0xff0087,
+ 199: 0xff00af,
+ 200: 0xff00d7,
+ 201: 0xff00ff,
+ 202: 0xff5f00,
+ 203: 0xff5f5f,
+ 204: 0xff5f87,
+ 205: 0xff5faf,
+ 206: 0xff5fd7,
+ 207: 0xff5fff,
+ 208: 0xff8700,
+ 209: 0xff875f,
+ 210: 0xff8787,
+ 211: 0xff87af,
+ 212: 0xff87d7,
+ 213: 0xff87ff,
+ 214: 0xffaf00,
+ 215: 0xffaf5f,
+ 216: 0xffaf87,
+ 217: 0xffafaf,
+ 218: 0xffafd7,
+ 219: 0xffafff,
+ 220: 0xffd700,
+ 221: 0xffd75f,
+ 222: 0xffd787,
+ 223: 0xffd7af,
+ 224: 0xffd7d7,
+ 225: 0xffd7ff,
+ 226: 0xffff00,
+ 227: 0xffff5f,
+ 228: 0xffff87,
+ 229: 0xffffaf,
+ 230: 0xffffd7,
+ 231: 0xffffff,
+ 232: 0x080808,
+ 233: 0x121212,
+ 234: 0x1c1c1c,
+ 235: 0x262626,
+ 236: 0x303030,
+ 237: 0x3a3a3a,
+ 238: 0x444444,
+ 239: 0x4e4e4e,
+ 240: 0x585858,
+ 241: 0x626262,
+ 242: 0x6c6c6c,
+ 243: 0x767676,
+ 244: 0x808080,
+ 245: 0x8a8a8a,
+ 246: 0x949494,
+ 247: 0x9e9e9e,
+ 248: 0xa8a8a8,
+ 249: 0xb2b2b2,
+ 250: 0xbcbcbc,
+ 251: 0xc6c6c6,
+ 252: 0xd0d0d0,
+ 253: 0xdadada,
+ 254: 0xe4e4e4,
+ 255: 0xeeeeee,
+}
+
+func (w *Writer) Write(data []byte) (n int, err error) {
+ var csbi consoleScreenBufferInfo
+ procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+
+ er := bytes.NewBuffer(data)
+loop:
+ for {
+ r1, _, err := procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+ if r1 == 0 {
+ break loop
+ }
+
+ c1, _, err := er.ReadRune()
+ if err != nil {
+ break loop
+ }
+ if c1 != 0x1b {
+ fmt.Fprint(w.out, string(c1))
+ continue
+ }
+ c2, _, err := er.ReadRune()
+ if err != nil {
+ w.lastbuf.WriteRune(c1)
+ break loop
+ }
+ if c2 != 0x5b {
+ w.lastbuf.WriteRune(c1)
+ w.lastbuf.WriteRune(c2)
+ continue
+ }
+
+ var buf bytes.Buffer
+ var m rune
+ for {
+ c, _, err := er.ReadRune()
+ if err != nil {
+ w.lastbuf.WriteRune(c1)
+ w.lastbuf.WriteRune(c2)
+ w.lastbuf.Write(buf.Bytes())
+ break loop
+ }
+ if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
+ m = c
+ break
+ }
+ buf.Write([]byte(string(c)))
+ }
+
+ var csbi consoleScreenBufferInfo
+ switch m {
+ case 'A':
+ n, err = strconv.Atoi(buf.String())
+ if err != nil {
+ continue
+ }
+ procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+ csbi.cursorPosition.y -= short(n)
+ procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+ case 'B':
+ n, err = strconv.Atoi(buf.String())
+ if err != nil {
+ continue
+ }
+ procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+ csbi.cursorPosition.y += short(n)
+ procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+ case 'C':
+ n, err = strconv.Atoi(buf.String())
+ if err != nil {
+ continue
+ }
+ procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+ csbi.cursorPosition.x -= short(n)
+ procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+ case 'D':
+ n, err = strconv.Atoi(buf.String())
+ if err != nil {
+ continue
+ }
+ if n, err = strconv.Atoi(buf.String()); err == nil {
+ var csbi consoleScreenBufferInfo
+ procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+ csbi.cursorPosition.x += short(n)
+ procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+ }
+ case 'E':
+ n, err = strconv.Atoi(buf.String())
+ if err != nil {
+ continue
+ }
+ procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+ csbi.cursorPosition.x = 0
+ csbi.cursorPosition.y += short(n)
+ procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+ case 'F':
+ n, err = strconv.Atoi(buf.String())
+ if err != nil {
+ continue
+ }
+ procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+ csbi.cursorPosition.x = 0
+ csbi.cursorPosition.y -= short(n)
+ procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+ case 'G':
+ n, err = strconv.Atoi(buf.String())
+ if err != nil {
+ continue
+ }
+ procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+ csbi.cursorPosition.x = short(n)
+ procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+ case 'H':
+ token := strings.Split(buf.String(), ";")
+ if len(token) != 2 {
+ continue
+ }
+ n1, err := strconv.Atoi(token[0])
+ if err != nil {
+ continue
+ }
+ n2, err := strconv.Atoi(token[1])
+ if err != nil {
+ continue
+ }
+ csbi.cursorPosition.x = short(n2)
+ csbi.cursorPosition.x = short(n1)
+ procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+ case 'J':
+ n, err := strconv.Atoi(buf.String())
+ if err != nil {
+ continue
+ }
+ var cursor coord
+ switch n {
+ case 0:
+ cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y}
+ case 1:
+ cursor = coord{x: csbi.window.left, y: csbi.window.top}
+ case 2:
+ cursor = coord{x: csbi.window.left, y: csbi.window.top}
+ }
+ var count, written dword
+ count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x)
+ procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
+ procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
+ case 'K':
+ n, err := strconv.Atoi(buf.String())
+ if err != nil {
+ continue
+ }
+ var cursor coord
+ switch n {
+ case 0:
+ cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y}
+ case 1:
+ cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y}
+ case 2:
+ cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y}
+ }
+ var count, written dword
+ count = dword(csbi.size.x - csbi.cursorPosition.x)
+ procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
+ procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
+ case 'm':
+ attr := csbi.attributes
+ cs := buf.String()
+ if cs == "" {
+ procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.oldattr))
+ continue
+ }
+ token := strings.Split(cs, ";")
+ for i := 0; i < len(token); i += 1 {
+ ns := token[i]
+ if n, err = strconv.Atoi(ns); err == nil {
+ switch {
+ case n == 0 || n == 100:
+ attr = w.oldattr
+ case 1 <= n && n <= 5:
+ attr |= foregroundIntensity
+ case n == 7:
+ attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4)
+ case 22 == n || n == 25 || n == 25:
+ attr |= foregroundIntensity
+ case n == 27:
+ attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4)
+ case 30 <= n && n <= 37:
+ attr = (attr & backgroundMask)
+ if (n-30)&1 != 0 {
+ attr |= foregroundRed
+ }
+ if (n-30)&2 != 0 {
+ attr |= foregroundGreen
+ }
+ if (n-30)&4 != 0 {
+ attr |= foregroundBlue
+ }
+ case n == 38: // set foreground color.
+ if i < len(token)-2 && (token[i+1] == "5" || token[i+1] == "05") {
+ if n256, err := strconv.Atoi(token[i+2]); err == nil {
+ if n256foreAttr == nil {
+ n256setup()
+ }
+ attr &= backgroundMask
+ attr |= n256foreAttr[n256]
+ i += 2
+ }
+ } else {
+ attr = attr & (w.oldattr & backgroundMask)
+ }
+ case n == 39: // reset foreground color.
+ attr &= backgroundMask
+ attr |= w.oldattr & foregroundMask
+ case 40 <= n && n <= 47:
+ attr = (attr & foregroundMask)
+ if (n-40)&1 != 0 {
+ attr |= backgroundRed
+ }
+ if (n-40)&2 != 0 {
+ attr |= backgroundGreen
+ }
+ if (n-40)&4 != 0 {
+ attr |= backgroundBlue
+ }
+ case n == 48: // set background color.
+ if i < len(token)-2 && token[i+1] == "5" {
+ if n256, err := strconv.Atoi(token[i+2]); err == nil {
+ if n256backAttr == nil {
+ n256setup()
+ }
+ attr &= foregroundMask
+ attr |= n256backAttr[n256]
+ i += 2
+ }
+ } else {
+ attr = attr & (w.oldattr & foregroundMask)
+ }
+ case n == 49: // reset foreground color.
+ attr &= foregroundMask
+ attr |= w.oldattr & backgroundMask
+ case 90 <= n && n <= 97:
+ attr = (attr & backgroundMask)
+ attr |= foregroundIntensity
+ if (n-90)&1 != 0 {
+ attr |= foregroundRed
+ }
+ if (n-90)&2 != 0 {
+ attr |= foregroundGreen
+ }
+ if (n-90)&4 != 0 {
+ attr |= foregroundBlue
+ }
+ case 100 <= n && n <= 107:
+ attr = (attr & foregroundMask)
+ attr |= backgroundIntensity
+ if (n-100)&1 != 0 {
+ attr |= backgroundRed
+ }
+ if (n-100)&2 != 0 {
+ attr |= backgroundGreen
+ }
+ if (n-100)&4 != 0 {
+ attr |= backgroundBlue
+ }
+ }
+ procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr))
+ }
+ }
+ }
+ }
+ return len(data) - w.lastbuf.Len(), nil
+}
+
+type consoleColor struct {
+ rgb int
+ red bool
+ green bool
+ blue bool
+ intensity bool
+}
+
+func (c consoleColor) foregroundAttr() (attr word) {
+ if c.red {
+ attr |= foregroundRed
+ }
+ if c.green {
+ attr |= foregroundGreen
+ }
+ if c.blue {
+ attr |= foregroundBlue
+ }
+ if c.intensity {
+ attr |= foregroundIntensity
+ }
+ return
+}
+
+func (c consoleColor) backgroundAttr() (attr word) {
+ if c.red {
+ attr |= backgroundRed
+ }
+ if c.green {
+ attr |= backgroundGreen
+ }
+ if c.blue {
+ attr |= backgroundBlue
+ }
+ if c.intensity {
+ attr |= backgroundIntensity
+ }
+ return
+}
+
+var color16 = []consoleColor{
+ consoleColor{0x000000, false, false, false, false},
+ consoleColor{0x000080, false, false, true, false},
+ consoleColor{0x008000, false, true, false, false},
+ consoleColor{0x008080, false, true, true, false},
+ consoleColor{0x800000, true, false, false, false},
+ consoleColor{0x800080, true, false, true, false},
+ consoleColor{0x808000, true, true, false, false},
+ consoleColor{0xc0c0c0, true, true, true, false},
+ consoleColor{0x808080, false, false, false, true},
+ consoleColor{0x0000ff, false, false, true, true},
+ consoleColor{0x00ff00, false, true, false, true},
+ consoleColor{0x00ffff, false, true, true, true},
+ consoleColor{0xff0000, true, false, false, true},
+ consoleColor{0xff00ff, true, false, true, true},
+ consoleColor{0xffff00, true, true, false, true},
+ consoleColor{0xffffff, true, true, true, true},
+}
+
+type hsv struct {
+ h, s, v float32
+}
+
+func (a hsv) dist(b hsv) float32 {
+ dh := a.h - b.h
+ switch {
+ case dh > 0.5:
+ dh = 1 - dh
+ case dh < -0.5:
+ dh = -1 - dh
+ }
+ ds := a.s - b.s
+ dv := a.v - b.v
+ return float32(math.Sqrt(float64(dh*dh + ds*ds + dv*dv)))
+}
+
+func toHSV(rgb int) hsv {
+ r, g, b := float32((rgb&0xFF0000)>>16)/256.0,
+ float32((rgb&0x00FF00)>>8)/256.0,
+ float32(rgb&0x0000FF)/256.0
+ min, max := minmax3f(r, g, b)
+ h := max - min
+ if h > 0 {
+ if max == r {
+ h = (g - b) / h
+ if h < 0 {
+ h += 6
+ }
+ } else if max == g {
+ h = 2 + (b-r)/h
+ } else {
+ h = 4 + (r-g)/h
+ }
+ }
+ h /= 6.0
+ s := max - min
+ if max != 0 {
+ s /= max
+ }
+ v := max
+ return hsv{h: h, s: s, v: v}
+}
+
+type hsvTable []hsv
+
+func toHSVTable(rgbTable []consoleColor) hsvTable {
+ t := make(hsvTable, len(rgbTable))
+ for i, c := range rgbTable {
+ t[i] = toHSV(c.rgb)
+ }
+ return t
+}
+
+func (t hsvTable) find(rgb int) consoleColor {
+ hsv := toHSV(rgb)
+ n := 7
+ l := float32(5.0)
+ for i, p := range t {
+ d := hsv.dist(p)
+ if d < l {
+ l, n = d, i
+ }
+ }
+ return color16[n]
+}
+
+func minmax3f(a, b, c float32) (min, max float32) {
+ if a < b {
+ if b < c {
+ return a, c
+ } else if a < c {
+ return a, b
+ } else {
+ return c, b
+ }
+ } else {
+ if a < c {
+ return b, c
+ } else if b < c {
+ return b, a
+ } else {
+ return c, a
+ }
+ }
+}
+
+var n256foreAttr []word
+var n256backAttr []word
+
+func n256setup() {
+ n256foreAttr = make([]word, 256)
+ n256backAttr = make([]word, 256)
+ t := toHSVTable(color16)
+ for i, rgb := range color256 {
+ c := t.find(rgb)
+ n256foreAttr[i] = c.foregroundAttr()
+ n256backAttr[i] = c.backgroundAttr()
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_appengine.go b/Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_appengine.go
new file mode 100644
index 000000000..83c588773
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_appengine.go
@@ -0,0 +1,9 @@
+// +build appengine
+
+package isatty
+
+// IsTerminal returns true if the file descriptor is terminal which
+// is always false on on appengine classic which is a sandboxed PaaS.
+func IsTerminal(fd uintptr) bool {
+ return false
+}
diff --git a/Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_bsd.go b/Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_bsd.go
index e6282b529..98ffe86a4 100644
--- a/Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_bsd.go
+++ b/Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_bsd.go
@@ -1,4 +1,5 @@
// +build darwin freebsd openbsd netbsd
+// +build !appengine
package isatty
diff --git a/Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_linux.go b/Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_linux.go
index 8b361d7fb..9d24bac1d 100644
--- a/Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_linux.go
+++ b/Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_linux.go
@@ -1,4 +1,5 @@
// +build linux
+// +build !appengine
package isatty
diff --git a/Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_solaris.go b/Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_solaris.go
new file mode 100644
index 000000000..1f0c6bf53
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_solaris.go
@@ -0,0 +1,16 @@
+// +build solaris
+// +build !appengine
+
+package isatty
+
+import (
+ "golang.org/x/sys/unix"
+)
+
+// IsTerminal returns true if the given file descriptor is a terminal.
+// see: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c
+func IsTerminal(fd uintptr) bool {
+ var termio unix.Termio
+ err := unix.IoctlSetTermio(int(fd), unix.TCGETA, &termio)
+ return err == nil
+}
diff --git a/Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_windows.go b/Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_windows.go
index 562ee39ca..83c398b16 100644
--- a/Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_windows.go
+++ b/Godeps/_workspace/src/github.com/mattn/go-isatty/isatty_windows.go
@@ -1,4 +1,5 @@
// +build windows
+// +build !appengine
package isatty
diff --git a/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth.go b/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth.go
index 0b417db15..3fbf33d59 100644
--- a/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth.go
+++ b/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth.go
@@ -352,24 +352,72 @@ func (c *Condition) StringWidth(s string) (width int) {
}
func (c *Condition) Truncate(s string, w int, tail string) string {
+ if c.StringWidth(s) <= w {
+ return s
+ }
r := []rune(s)
- tw := StringWidth(tail)
+ tw := c.StringWidth(tail)
w -= tw
width := 0
i := 0
for ; i < len(r); i++ {
- cw := RuneWidth(r[i])
+ cw := c.RuneWidth(r[i])
if width+cw > w {
break
}
width += cw
}
- if i == len(r) {
- return string(r[0:i])
- }
return string(r[0:i]) + tail
}
+func (c *Condition) Wrap(s string, w int) string {
+ width := 0
+ out := ""
+ for _, r := range []rune(s) {
+ cw := RuneWidth(r)
+ if r == '\n' {
+ out += string(r)
+ width = 0
+ continue
+ } else if width+cw > w {
+ out += "\n"
+ width = 0
+ out += string(r)
+ width += cw
+ continue
+ }
+ out += string(r)
+ width += cw
+ }
+ return out
+}
+
+func (c *Condition) FillLeft(s string, w int) string {
+ width := c.StringWidth(s)
+ count := w - width
+ if count > 0 {
+ b := make([]byte, count)
+ for i := range b {
+ b[i] = ' '
+ }
+ return string(b) + s
+ }
+ return s
+}
+
+func (c *Condition) FillRight(s string, w int) string {
+ width := c.StringWidth(s)
+ count := w - width
+ if count > 0 {
+ b := make([]byte, count)
+ for i := range b {
+ b[i] = ' '
+ }
+ return s + string(b)
+ }
+ return s
+}
+
// RuneWidth returns the number of cells in r.
// See http://www.unicode.org/reports/tr11/
func RuneWidth(r rune) int {
@@ -402,3 +450,15 @@ func StringWidth(s string) (width int) {
func Truncate(s string, w int, tail string) string {
return DefaultCondition.Truncate(s, w, tail)
}
+
+func Wrap(s string, w int) string {
+ return DefaultCondition.Wrap(s, w)
+}
+
+func FillLeft(s string, w int) string {
+ return DefaultCondition.FillLeft(s, w)
+}
+
+func FillRight(s string, w int) string {
+ return DefaultCondition.FillRight(s, w)
+}
diff --git a/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_test.go b/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_test.go
deleted file mode 100644
index 5cef3d6a4..000000000
--- a/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_test.go
+++ /dev/null
@@ -1,134 +0,0 @@
-package runewidth
-
-import (
- "testing"
-)
-
-var runewidthtests = []struct {
- in rune
- out int
-}{
- {'世', 2},
- {'界', 2},
- {'セ', 1},
- {'カ', 1},
- {'イ', 1},
- {'☆', 2}, // double width in ambiguous
- {'\x00', 0},
- {'\x01', 1},
- {'\u0300', 0},
-}
-
-func TestRuneWidth(t *testing.T) {
- c := NewCondition()
- c.EastAsianWidth = true
- for _, tt := range runewidthtests {
- if out := c.RuneWidth(tt.in); out != tt.out {
- t.Errorf("Width(%q) = %v, want %v", tt.in, out, tt.out)
- }
- }
-}
-
-var isambiguouswidthtests = []struct {
- in rune
- out bool
-}{
- {'世', false},
- {'■', true},
- {'界', false},
- {'○', true},
- {'㈱', false},
- {'①', true},
- {'②', true},
- {'③', true},
- {'④', true},
- {'⑤', true},
- {'⑥', true},
- {'⑦', true},
- {'⑧', true},
- {'⑨', true},
- {'⑩', true},
- {'⑪', true},
- {'⑫', true},
- {'⑬', true},
- {'⑭', true},
- {'⑮', true},
- {'⑯', true},
- {'⑰', true},
- {'⑱', true},
- {'⑲', true},
- {'⑳', true},
- {'☆', true},
-}
-
-func TestIsAmbiguousWidth(t *testing.T) {
- for _, tt := range isambiguouswidthtests {
- if out := IsAmbiguousWidth(tt.in); out != tt.out {
- t.Errorf("IsAmbiguousWidth(%q) = %v, want %v", tt.in, out, tt.out)
- }
- }
-}
-
-var stringwidthtests = []struct {
- in string
- out int
-}{
- {"■㈱の世界①", 12},
- {"スター☆", 8},
-}
-
-func TestStringWidth(t *testing.T) {
- c := NewCondition()
- c.EastAsianWidth = true
- for _, tt := range stringwidthtests {
- if out := c.StringWidth(tt.in); out != tt.out {
- t.Errorf("StringWidth(%q) = %v, want %v", tt.in, out, tt.out)
- }
- }
-}
-
-func TestStringWidthInvalid(t *testing.T) {
- s := "こんにちわ\x00世界"
- if out := StringWidth(s); out != 14 {
- t.Errorf("StringWidth(%q) = %v, want %v", s, out, 14)
- }
-}
-
-func TestTruncate(t *testing.T) {
- s := "あいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおおおおお"
- expected := "あいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおお..."
-
- if out := Truncate(s, 80, "..."); out != expected {
- t.Errorf("Truncate(%q) = %v, want %v", s, out, expected)
- }
-}
-
-func TestTruncateNoNeeded(t *testing.T) {
- s := "あいうえおあい"
- expected := "あいうえおあい"
-
- if out := Truncate(s, 80, "..."); out != expected {
- t.Errorf("Truncate(%q) = %v, want %v", s, out, expected)
- }
-}
-
-var isneutralwidthtests = []struct {
- in rune
- out bool
-}{
- {'→', false},
- {'┊', false},
- {'┈', false},
- {'~', false},
- {'└', false},
- {'⣀', true},
- {'⣀', true},
-}
-
-func TestIsNeutralWidth(t *testing.T) {
- for _, tt := range isneutralwidthtests {
- if out := IsNeutralWidth(tt.in); out != tt.out {
- t.Errorf("IsNeutralWidth(%q) = %v, want %v", tt.in, out, tt.out)
- }
- }
-}
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/README.md b/Godeps/_workspace/src/github.com/nsf/termbox-go/README.md
index 5fc1874b1..6ff10c6b9 100644
--- a/Godeps/_workspace/src/github.com/nsf/termbox-go/README.md
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/README.md
@@ -18,6 +18,8 @@ There are also some interesting projects using termbox-go:
- [termui](https://github.com/gizak/termui) is a terminal dashboard.
- [termloop](https://github.com/JoelOtter/termloop) is a terminal game engine.
- [xterm-color-chart](https://github.com/kutuluk/xterm-color-chart) is a XTerm 256 color chart.
+ - [gocui](https://github.com/jroimartin/gocui) is a minimalist Go library aimed at creating console user interfaces.
+ - [dry](https://github.com/moncho/dry) is an interactive cli to manage Docker containers.
### API reference
[godoc.org/github.com/nsf/termbox-go](http://godoc.org/github.com/nsf/termbox-go)
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/api.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/api.go
index 1e284060e..b8497b02e 100644
--- a/Godeps/_workspace/src/github.com/nsf/termbox-go/api.go
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/api.go
@@ -372,7 +372,7 @@ func Clear(fg, bg Attribute) error {
// any known sequence. ESC enables ModAlt modifier for the next keyboard event.
//
// Both input modes can be OR'ed with Mouse mode. Setting Mouse mode bit up will
-// enable mouse button click events.
+// enable mouse button press/release and drag events.
//
// If 'mode' is InputCurrent, returns the current input mode. See also Input*
// constants.
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/api_common.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/api_common.go
index c0069fb28..9f23661f5 100644
--- a/Godeps/_workspace/src/github.com/nsf/termbox-go/api_common.go
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/api_common.go
@@ -70,6 +70,9 @@ const (
MouseLeft
MouseMiddle
MouseRight
+ MouseRelease
+ MouseWheelUp
+ MouseWheelDown
)
const (
@@ -123,7 +126,8 @@ const (
// Alt modifier constant, see Event.Mod field and SetInputMode function.
const (
- ModAlt Modifier = 0x01
+ ModAlt Modifier = 1 << iota
+ ModMotion
)
// Cell colors, you can combine a color with multiple attributes using bitwise
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/api_windows.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/api_windows.go
index 203544bbf..7def30a67 100644
--- a/Godeps/_workspace/src/github.com/nsf/termbox-go/api_windows.go
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/api_windows.go
@@ -81,8 +81,8 @@ func Close() {
cancel_comm <- true
set_event(interrupt)
select {
- case <-input_comm:
- default:
+ case <-input_comm:
+ default:
}
<-cancel_done_comm
@@ -198,7 +198,7 @@ func Clear(fg, bg Attribute) error {
// any known sequence. ESC enables ModAlt modifier for the next keyboard event.
//
// Both input modes can be OR'ed with Mouse mode. Setting Mouse mode bit up will
-// enable mouse button click events.
+// enable mouse button press/release and drag events.
//
// If 'mode' is InputCurrent, returns the current input mode. See also Input*
// constants.
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox.go
index f754880d2..6e5ba6c8f 100644
--- a/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox.go
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox.go
@@ -287,31 +287,131 @@ func tcgetattr(fd uintptr, termios *syscall_Termios) error {
return nil
}
-func parse_escape_sequence(event *Event, buf []byte) (int, bool) {
- bufstr := string(buf)
- // mouse
- if len(bufstr) >= 6 && strings.HasPrefix(bufstr, "\033[M") {
- switch buf[3] & 3 {
+func parse_mouse_event(event *Event, buf string) (int, bool) {
+ if strings.HasPrefix(buf, "\033[M") && len(buf) >= 6 {
+ // X10 mouse encoding, the simplest one
+ // \033 [ M Cb Cx Cy
+ b := buf[3] - 32
+ switch b & 3 {
case 0:
- event.Key = MouseLeft
+ if b&64 != 0 {
+ event.Key = MouseWheelUp
+ } else {
+ event.Key = MouseLeft
+ }
case 1:
- event.Key = MouseMiddle
+ if b&64 != 0 {
+ event.Key = MouseWheelDown
+ } else {
+ event.Key = MouseMiddle
+ }
case 2:
event.Key = MouseRight
case 3:
+ event.Key = MouseRelease
+ default:
return 6, false
}
event.Type = EventMouse // KeyEvent by default
- // wheel up outputs MouseLeft
- if buf[3] == 0x60 || buf[3] == 0x70 {
- event.Key = MouseMiddle
+ if b&32 != 0 {
+ event.Mod |= ModMotion
}
+
// the coord is 1,1 for upper left
event.MouseX = int(buf[4]) - 1 - 32
event.MouseY = int(buf[5]) - 1 - 32
return 6, true
+ } else if strings.HasPrefix(buf, "\033[<") || strings.HasPrefix(buf, "\033[") {
+ // xterm 1006 extended mode or urxvt 1015 extended mode
+ // xterm: \033 [ < Cb ; Cx ; Cy (M or m)
+ // urxvt: \033 [ Cb ; Cx ; Cy M
+
+ // find the first M or m, that's where we stop
+ mi := strings.IndexAny(buf, "Mm")
+ if mi == -1 {
+ return 0, false
+ }
+
+ // whether it's a capital M or not
+ isM := buf[mi] == 'M'
+
+ // whether it's urxvt or not
+ isU := false
+
+ // buf[2] is safe here, because having M or m found means we have at
+ // least 3 bytes in a string
+ if buf[2] == '<' {
+ buf = buf[3:mi]
+ } else {
+ isU = true
+ buf = buf[2:mi]
+ }
+
+ s1 := strings.Index(buf, ";")
+ s2 := strings.LastIndex(buf, ";")
+ // not found or only one ';'
+ if s1 == -1 || s2 == -1 || s1 == s2 {
+ return 0, false
+ }
+
+ n1, err := strconv.ParseInt(buf[0:s1], 10, 64)
+ if err != nil {
+ return 0, false
+ }
+ n2, err := strconv.ParseInt(buf[s1+1:s2], 10, 64)
+ if err != nil {
+ return 0, false
+ }
+ n3, err := strconv.ParseInt(buf[s2+1:], 10, 64)
+ if err != nil {
+ return 0, false
+ }
+
+ // on urxvt, first number is encoded exactly as in X10, but we need to
+ // make it zero-based, on xterm it is zero-based already
+ if isU {
+ n1 -= 32
+ }
+ switch n1 & 3 {
+ case 0:
+ if n1&64 != 0 {
+ event.Key = MouseWheelUp
+ } else {
+ event.Key = MouseLeft
+ }
+ case 1:
+ if n1&64 != 0 {
+ event.Key = MouseWheelDown
+ } else {
+ event.Key = MouseMiddle
+ }
+ case 2:
+ event.Key = MouseRight
+ case 3:
+ event.Key = MouseRelease
+ default:
+ return mi + 1, false
+ }
+ if !isM {
+ // on xterm mouse release is signaled by lowercase m
+ event.Key = MouseRelease
+ }
+
+ event.Type = EventMouse // KeyEvent by default
+ if n1&32 != 0 {
+ event.Mod |= ModMotion
+ }
+
+ event.MouseX = int(n2) - 1
+ event.MouseY = int(n3) - 1
+ return mi + 1, true
}
+ return 0, false
+}
+
+func parse_escape_sequence(event *Event, buf []byte) (int, bool) {
+ bufstr := string(buf)
for i, key := range keys {
if strings.HasPrefix(bufstr, key) {
event.Ch = 0
@@ -319,7 +419,9 @@ func parse_escape_sequence(event *Event, buf []byte) (int, bool) {
return len(key), true
}
}
- return 0, true
+
+ // if none of the keys match, let's try mouse seqences
+ return parse_mouse_event(event, bufstr)
}
func extract_raw_event(data []byte, event *Event) bool {
@@ -349,8 +451,7 @@ func extract_event(inbuf []byte, event *Event) bool {
if inbuf[0] == '\033' {
// possible escape sequence
- n, ok := parse_escape_sequence(event, inbuf)
- if n != 0 {
+ if n, ok := parse_escape_sequence(event, inbuf); n != 0 {
event.N = n
return ok
}
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox_windows.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox_windows.go
index f345d0eb0..f7dad7b8a 100644
--- a/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox_windows.go
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox_windows.go
@@ -522,8 +522,16 @@ func prepare_diff_messages() {
}
}
+func get_ct(table []word, idx int) word {
+ idx = idx & 0x0F
+ if idx >= len(table) {
+ idx = len(table) - 1
+ }
+ return table[idx]
+}
+
func cell_to_char_info(c Cell) (attr word, wc [2]wchar) {
- attr = color_table_fg[c.Fg&0x0F] | color_table_bg[c.Bg&0x0F]
+ attr = get_ct(color_table_fg, int(c.Fg)) | get_ct(color_table_bg, int(c.Bg))
if c.Fg&AttrReverse|c.Bg&AttrReverse != 0 {
attr = (attr&0xF0)>>4 | (attr&0x0F)<<4
}
@@ -744,7 +752,9 @@ func input_event_producer() {
var r input_record
var err error
var last_button Key
+ var last_button_pressed Key
var last_state = dword(0)
+ var last_x, last_y = -1, -1
handles := []syscall.Handle{in, interrupt}
for {
err = wait_for_multiple_objects(handles)
@@ -782,31 +792,64 @@ func input_event_producer() {
}
case mouse_event:
mr := *(*mouse_event_record)(unsafe.Pointer(&r.event))
-
- // single or double click
+ ev := Event{Type: EventMouse}
switch mr.event_flags {
- case 0:
+ case 0, 2:
+ // single or double click
cur_state := mr.button_state
switch {
case last_state&mouse_lmb == 0 && cur_state&mouse_lmb != 0:
last_button = MouseLeft
+ last_button_pressed = last_button
case last_state&mouse_rmb == 0 && cur_state&mouse_rmb != 0:
last_button = MouseRight
+ last_button_pressed = last_button
case last_state&mouse_mmb == 0 && cur_state&mouse_mmb != 0:
last_button = MouseMiddle
+ last_button_pressed = last_button
+ case last_state&mouse_lmb != 0 && cur_state&mouse_lmb == 0:
+ last_button = MouseRelease
+ case last_state&mouse_rmb != 0 && cur_state&mouse_rmb == 0:
+ last_button = MouseRelease
+ case last_state&mouse_mmb != 0 && cur_state&mouse_mmb == 0:
+ last_button = MouseRelease
default:
last_state = cur_state
continue
}
last_state = cur_state
- fallthrough
- case 2:
- input_comm <- Event{
- Type: EventMouse,
- Key: last_button,
- MouseX: int(mr.mouse_pos.x),
- MouseY: int(mr.mouse_pos.y),
+ ev.Key = last_button
+ last_x, last_y = int(mr.mouse_pos.x), int(mr.mouse_pos.y)
+ ev.MouseX = last_x
+ ev.MouseY = last_y
+ case 1:
+ // mouse motion
+ x, y := int(mr.mouse_pos.x), int(mr.mouse_pos.y)
+ if last_state != 0 && (last_x != x || last_y != y) {
+ ev.Key = last_button_pressed
+ ev.Mod = ModMotion
+ ev.MouseX = x
+ ev.MouseY = y
+ last_x, last_y = x, y
+ } else {
+ ev.Type = EventNone
+ }
+ case 4:
+ // mouse wheel
+ n := int16(mr.button_state >> 16)
+ if n > 0 {
+ ev.Key = MouseWheelUp
+ } else {
+ ev.Key = MouseWheelDown
}
+ last_x, last_y = int(mr.mouse_pos.x), int(mr.mouse_pos.y)
+ ev.MouseX = last_x
+ ev.MouseY = last_y
+ default:
+ ev.Type = EventNone
+ }
+ if ev.Type != EventNone {
+ input_comm <- ev
}
}
}
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/terminfo.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/terminfo.go
index 3569e3c0e..35dbd70b8 100644
--- a/Godeps/_workspace/src/github.com/nsf/termbox-go/terminfo.go
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/terminfo.go
@@ -23,6 +23,8 @@ import (
const (
ti_magic = 0432
ti_header_length = 12
+ ti_mouse_enter = "\x1b[?1000h\x1b[?1002h\x1b[?1015h\x1b[?1006h"
+ ti_mouse_leave = "\x1b[?1006l\x1b[?1015l\x1b[?1002l\x1b[?1000l"
)
func load_terminfo() ([]byte, error) {
@@ -172,8 +174,8 @@ func setup_term() (err error) {
return
}
}
- funcs[t_max_funcs-2] = "\x1b[?1000h"
- funcs[t_max_funcs-1] = "\x1b[?1000l"
+ funcs[t_max_funcs-2] = ti_mouse_enter
+ funcs[t_max_funcs-1] = ti_mouse_leave
return nil
}
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/terminfo_builtin.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/terminfo_builtin.go
index 6f927c852..a94866067 100644
--- a/Godeps/_workspace/src/github.com/nsf/termbox-go/terminfo_builtin.go
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/terminfo_builtin.go
@@ -15,7 +15,7 @@ var screen_keys = []string{
"\x1bOP", "\x1bOQ", "\x1bOR", "\x1bOS", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[1~", "\x1b[4~", "\x1b[5~", "\x1b[6~", "\x1bOA", "\x1bOB", "\x1bOD", "\x1bOC",
}
var screen_funcs = []string{
- "\x1b[?1049h", "\x1b[?1049l", "\x1b[34h\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[J", "\x1b[m\x0f", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "\x1b[?1h\x1b=", "\x1b[?1l\x1b>", "\x1b[?1000h", "\x1b[?1000l",
+ "\x1b[?1049h", "\x1b[?1049l", "\x1b[34h\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[J", "\x1b[m\x0f", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "\x1b[?1h\x1b=", "\x1b[?1l\x1b>", ti_mouse_enter, ti_mouse_leave,
}
// xterm
@@ -23,7 +23,7 @@ var xterm_keys = []string{
"\x1bOP", "\x1bOQ", "\x1bOR", "\x1bOS", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1bOH", "\x1bOF", "\x1b[5~", "\x1b[6~", "\x1bOA", "\x1bOB", "\x1bOD", "\x1bOC",
}
var xterm_funcs = []string{
- "\x1b[?1049h", "\x1b[?1049l", "\x1b[?12l\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[2J", "\x1b(B\x1b[m", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "\x1b[?1h\x1b=", "\x1b[?1l\x1b>", "\x1b[?1000h", "\x1b[?1000l",
+ "\x1b[?1049h", "\x1b[?1049l", "\x1b[?12l\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[2J", "\x1b(B\x1b[m", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "\x1b[?1h\x1b=", "\x1b[?1l\x1b>", ti_mouse_enter, ti_mouse_leave,
}
// rxvt-unicode
@@ -31,7 +31,7 @@ var rxvt_unicode_keys = []string{
"\x1b[11~", "\x1b[12~", "\x1b[13~", "\x1b[14~", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[7~", "\x1b[8~", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C",
}
var rxvt_unicode_funcs = []string{
- "\x1b[?1049h", "\x1b[r\x1b[?1049l", "\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[2J", "\x1b[m\x1b(B", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "\x1b=", "\x1b>", "\x1b[?1000h", "\x1b[?1000l",
+ "\x1b[?1049h", "\x1b[r\x1b[?1049l", "\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[2J", "\x1b[m\x1b(B", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "\x1b=", "\x1b>", ti_mouse_enter, ti_mouse_leave,
}
// linux
@@ -47,7 +47,7 @@ var rxvt_256color_keys = []string{
"\x1b[11~", "\x1b[12~", "\x1b[13~", "\x1b[14~", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[7~", "\x1b[8~", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C",
}
var rxvt_256color_funcs = []string{
- "\x1b7\x1b[?47h", "\x1b[2J\x1b[?47l\x1b8", "\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[2J", "\x1b[m\x0f", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "\x1b=", "\x1b>", "\x1b[?1000h", "\x1b[?1000l",
+ "\x1b7\x1b[?47h", "\x1b[2J\x1b[?47l\x1b8", "\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[2J", "\x1b[m\x0f", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "\x1b=", "\x1b>", ti_mouse_enter, ti_mouse_leave,
}
var terms = []struct {
diff --git a/Godeps/_workspace/src/github.com/pborman/uuid/.travis.yml b/Godeps/_workspace/src/github.com/pborman/uuid/.travis.yml
new file mode 100644
index 000000000..a6a98db8a
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/pborman/uuid/.travis.yml
@@ -0,0 +1,10 @@
+language: go
+
+go:
+ - 1.4.3
+ - 1.5.3
+ - release
+ - tip
+
+script:
+ - go test -v ./...
diff --git a/Godeps/_workspace/src/github.com/pborman/uuid/README.md b/Godeps/_workspace/src/github.com/pborman/uuid/README.md
new file mode 100644
index 000000000..f023d47ca
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/pborman/uuid/README.md
@@ -0,0 +1,13 @@
+This project was automatically exported from code.google.com/p/go-uuid
+
+# uuid ![build status](https://travis-ci.org/pborman/uuid.svg?branch=master)
+The uuid package generates and inspects UUIDs based on [RFC 412](http://tools.ietf.org/html/rfc4122) and DCE 1.1: Authentication and Security Services.
+
+###### Install
+`go get github.com/pborman/uuid`
+
+###### Documentation
+[![GoDoc](https://godoc.org/github.com/pborman/uuid?status.svg)](http://godoc.org/github.com/pborman/uuid)
+
+Full `go doc` style documentation for the package can be viewed online without installing this package by using the GoDoc site here:
+http://godoc.org/github.com/pborman/uuid
diff --git a/Godeps/_workspace/src/github.com/pborman/uuid/hash.go b/Godeps/_workspace/src/github.com/pborman/uuid/hash.go
index cdd4192fd..a0420c1ef 100644
--- a/Godeps/_workspace/src/github.com/pborman/uuid/hash.go
+++ b/Godeps/_workspace/src/github.com/pborman/uuid/hash.go
@@ -19,7 +19,7 @@ var (
NIL = Parse("00000000-0000-0000-0000-000000000000")
)
-// NewHash returns a new UUID dervied from the hash of space concatenated with
+// NewHash returns a new UUID derived from the hash of space concatenated with
// data generated by h. The hash should be at least 16 byte in length. The
// first 16 bytes of the hash are used to form the UUID. The version of the
// UUID will be the lower 4 bits of version. NewHash is used to implement
diff --git a/Godeps/_workspace/src/github.com/pborman/uuid/json.go b/Godeps/_workspace/src/github.com/pborman/uuid/json.go
index 760580a50..9dda1dfba 100644
--- a/Godeps/_workspace/src/github.com/pborman/uuid/json.go
+++ b/Godeps/_workspace/src/github.com/pborman/uuid/json.go
@@ -7,17 +7,21 @@ package uuid
import "errors"
func (u UUID) MarshalJSON() ([]byte, error) {
- if len(u) == 0 {
+ if len(u) != 16 {
return []byte(`""`), nil
}
- return []byte(`"` + u.String() + `"`), nil
+ var js [38]byte
+ js[0] = '"'
+ encodeHex(js[1:], u)
+ js[37] = '"'
+ return js[:], nil
}
func (u *UUID) UnmarshalJSON(data []byte) error {
- if len(data) == 0 || string(data) == `""` {
+ if string(data) == `""` {
return nil
}
- if len(data) < 2 || data[0] != '"' || data[len(data)-1] != '"' {
+ if data[0] != '"' {
return errors.New("invalid UUID format")
}
data = data[1 : len(data)-1]
diff --git a/Godeps/_workspace/src/github.com/pborman/uuid/json_test.go b/Godeps/_workspace/src/github.com/pborman/uuid/json_test.go
deleted file mode 100644
index b5eae0924..000000000
--- a/Godeps/_workspace/src/github.com/pborman/uuid/json_test.go
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2014 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package uuid
-
-import (
- "encoding/json"
- "reflect"
- "testing"
-)
-
-var testUUID = Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
-
-func TestJSON(t *testing.T) {
- type S struct {
- ID1 UUID
- ID2 UUID
- }
- s1 := S{ID1: testUUID}
- data, err := json.Marshal(&s1)
- if err != nil {
- t.Fatal(err)
- }
- var s2 S
- if err := json.Unmarshal(data, &s2); err != nil {
- t.Fatal(err)
- }
- if !reflect.DeepEqual(&s1, &s2) {
- t.Errorf("got %#v, want %#v", s2, s1)
- }
-}
diff --git a/Godeps/_workspace/src/github.com/pborman/uuid/node.go b/Godeps/_workspace/src/github.com/pborman/uuid/node.go
index dd0a8ac18..42d60da8f 100644
--- a/Godeps/_workspace/src/github.com/pborman/uuid/node.go
+++ b/Godeps/_workspace/src/github.com/pborman/uuid/node.go
@@ -4,9 +4,13 @@
package uuid
-import "net"
+import (
+ "net"
+ "sync"
+)
var (
+ nodeMu sync.Mutex
interfaces []net.Interface // cached list of interfaces
ifname string // name of interface being used
nodeID []byte // hardware for version 1 UUIDs
@@ -16,6 +20,8 @@ var (
// derived. The interface "user" is returned if the NodeID was set by
// SetNodeID.
func NodeInterface() string {
+ defer nodeMu.Unlock()
+ nodeMu.Lock()
return ifname
}
@@ -26,6 +32,12 @@ func NodeInterface() string {
//
// SetNodeInterface never fails when name is "".
func SetNodeInterface(name string) bool {
+ defer nodeMu.Unlock()
+ nodeMu.Lock()
+ return setNodeInterface(name)
+}
+
+func setNodeInterface(name string) bool {
if interfaces == nil {
var err error
interfaces, err = net.Interfaces()
@@ -59,8 +71,10 @@ func SetNodeInterface(name string) bool {
// NodeID returns a slice of a copy of the current Node ID, setting the Node ID
// if not already set.
func NodeID() []byte {
+ defer nodeMu.Unlock()
+ nodeMu.Lock()
if nodeID == nil {
- SetNodeInterface("")
+ setNodeInterface("")
}
nid := make([]byte, 6)
copy(nid, nodeID)
@@ -71,6 +85,8 @@ func NodeID() []byte {
// of id are used. If id is less than 6 bytes then false is returned and the
// Node ID is not set.
func SetNodeID(id []byte) bool {
+ defer nodeMu.Unlock()
+ nodeMu.Lock()
if setNodeID(id) {
ifname = "user"
return true
diff --git a/Godeps/_workspace/src/github.com/pborman/uuid/seq_test.go b/Godeps/_workspace/src/github.com/pborman/uuid/seq_test.go
deleted file mode 100644
index 3b3d1430d..000000000
--- a/Godeps/_workspace/src/github.com/pborman/uuid/seq_test.go
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2014 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package uuid
-
-import (
- "flag"
- "runtime"
- "testing"
- "time"
-)
-
-// This test is only run when --regressions is passed on the go test line.
-var regressions = flag.Bool("regressions", false, "run uuid regression tests")
-
-// TestClockSeqRace tests for a particular race condition of returning two
-// identical Version1 UUIDs. The duration of 1 minute was chosen as the race
-// condition, before being fixed, nearly always occured in under 30 seconds.
-func TestClockSeqRace(t *testing.T) {
- if !*regressions {
- t.Skip("skipping regression tests")
- }
- duration := time.Minute
-
- done := make(chan struct{})
- defer close(done)
-
- ch := make(chan UUID, 10000)
- ncpu := runtime.NumCPU()
- switch ncpu {
- case 0, 1:
- // We can't run the test effectively.
- t.Skip("skipping race test, only one CPU detected")
- return
- default:
- runtime.GOMAXPROCS(ncpu)
- }
- for i := 0; i < ncpu; i++ {
- go func() {
- for {
- select {
- case <-done:
- return
- case ch <- NewUUID():
- }
- }
- }()
- }
-
- uuids := make(map[string]bool)
- cnt := 0
- start := time.Now()
- for u := range ch {
- s := u.String()
- if uuids[s] {
- t.Errorf("duplicate uuid after %d in %v: %s", cnt, time.Since(start), s)
- return
- }
- uuids[s] = true
- if time.Since(start) > duration {
- return
- }
- cnt++
- }
-}
diff --git a/Godeps/_workspace/src/github.com/pborman/uuid/sql.go b/Godeps/_workspace/src/github.com/pborman/uuid/sql.go
index 2d7679e2a..d015bfd13 100644
--- a/Godeps/_workspace/src/github.com/pborman/uuid/sql.go
+++ b/Godeps/_workspace/src/github.com/pborman/uuid/sql.go
@@ -5,6 +5,7 @@
package uuid
import (
+ "database/sql/driver"
"errors"
"fmt"
)
@@ -15,6 +16,11 @@ import (
func (uuid *UUID) Scan(src interface{}) error {
switch src.(type) {
case string:
+ // if an empty UUID comes from a table, we return a null UUID
+ if src.(string) == "" {
+ return nil
+ }
+
// see uuid.Parse for required string format
parsed := Parse(src.(string))
@@ -24,17 +30,37 @@ func (uuid *UUID) Scan(src interface{}) error {
*uuid = parsed
case []byte:
- // assumes a simple slice of bytes, just check validity and store
- u := UUID(src.([]byte))
+ b := src.([]byte)
- if u.Variant() == Invalid {
- return errors.New("Scan: invalid UUID format")
+ // if an empty UUID comes from a table, we return a null UUID
+ if len(b) == 0 {
+ return nil
+ }
+
+ // assumes a simple slice of bytes if 16 bytes
+ // otherwise attempts to parse
+ if len(b) == 16 {
+ *uuid = UUID(b)
+ } else {
+ u := Parse(string(b))
+
+ if u == nil {
+ return errors.New("Scan: invalid UUID format")
+ }
+
+ *uuid = u
}
- *uuid = u
default:
return fmt.Errorf("Scan: unable to scan type %T into UUID", src)
}
return nil
}
+
+// Value implements sql.Valuer so that UUIDs can be written to databases
+// transparently. Currently, UUIDs map to strings. Please consult
+// database-specific driver documentation for matching types.
+func (uuid UUID) Value() (driver.Value, error) {
+ return uuid.String(), nil
+}
diff --git a/Godeps/_workspace/src/github.com/pborman/uuid/sql_test.go b/Godeps/_workspace/src/github.com/pborman/uuid/sql_test.go
deleted file mode 100644
index d643567ee..000000000
--- a/Godeps/_workspace/src/github.com/pborman/uuid/sql_test.go
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2015 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package uuid
-
-import (
- "strings"
- "testing"
-)
-
-func TestScan(t *testing.T) {
- var stringTest string = "f47ac10b-58cc-0372-8567-0e02b2c3d479"
- var byteTest []byte = Parse(stringTest)
- var badTypeTest int = 6
- var invalidTest string = "f47ac10b-58cc-0372-8567-0e02b2c3d4"
- var invalidByteTest []byte = Parse(invalidTest)
-
- var uuid UUID
- err := (&uuid).Scan(stringTest)
- if err != nil {
- t.Fatal(err)
- }
-
- err = (&uuid).Scan(byteTest)
- if err != nil {
- t.Fatal(err)
- }
-
- err = (&uuid).Scan(badTypeTest)
- if err == nil {
- t.Error("int correctly parsed and shouldn't have")
- }
- if !strings.Contains(err.Error(), "unable to scan type") {
- t.Error("attempting to parse an int returned an incorrect error message")
- }
-
- err = (&uuid).Scan(invalidTest)
- if err == nil {
- t.Error("invalid uuid was parsed without error")
- }
- if !strings.Contains(err.Error(), "invalid UUID") {
- t.Error("attempting to parse an invalid UUID returned an incorrect error message")
- }
-
- err = (&uuid).Scan(invalidByteTest)
- if err == nil {
- t.Error("invalid byte uuid was parsed without error")
- }
- if !strings.Contains(err.Error(), "invalid UUID") {
- t.Error("attempting to parse an invalid byte UUID returned an incorrect error message")
- }
-}
diff --git a/Godeps/_workspace/src/github.com/pborman/uuid/time.go b/Godeps/_workspace/src/github.com/pborman/uuid/time.go
index 7ebc9bef1..eedf24219 100644
--- a/Godeps/_workspace/src/github.com/pborman/uuid/time.go
+++ b/Godeps/_workspace/src/github.com/pborman/uuid/time.go
@@ -23,7 +23,7 @@ const (
)
var (
- mu sync.Mutex
+ timeMu sync.Mutex
lasttime uint64 // last time we returned
clock_seq uint16 // clock sequence for this run
@@ -43,8 +43,8 @@ func (t Time) UnixTime() (sec, nsec int64) {
// clock sequence as well as adjusting the clock sequence as needed. An error
// is returned if the current time cannot be determined.
func GetTime() (Time, uint16, error) {
- defer mu.Unlock()
- mu.Lock()
+ defer timeMu.Unlock()
+ timeMu.Lock()
return getTime()
}
@@ -75,8 +75,8 @@ func getTime() (Time, uint16, error) {
// ClockSequence, GetTime, or NewUUID. (section 4.2.1.1) sequence is generated
// for
func ClockSequence() int {
- defer mu.Unlock()
- mu.Lock()
+ defer timeMu.Unlock()
+ timeMu.Lock()
return clockSequence()
}
@@ -90,8 +90,8 @@ func clockSequence() int {
// SetClockSeq sets the clock sequence to the lower 14 bits of seq. Setting to
// -1 causes a new sequence to be generated.
func SetClockSequence(seq int) {
- defer mu.Unlock()
- mu.Lock()
+ defer timeMu.Unlock()
+ timeMu.Lock()
setClockSequence(seq)
}
diff --git a/Godeps/_workspace/src/github.com/pborman/uuid/util.go b/Godeps/_workspace/src/github.com/pborman/uuid/util.go
index de40b102c..fc8e052c7 100644
--- a/Godeps/_workspace/src/github.com/pborman/uuid/util.go
+++ b/Godeps/_workspace/src/github.com/pborman/uuid/util.go
@@ -16,7 +16,7 @@ func randomBits(b []byte) {
}
// xvalues returns the value of a byte as a hexadecimal digit or 255.
-var xvalues = []byte{
+var xvalues = [256]byte{
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
diff --git a/Godeps/_workspace/src/github.com/pborman/uuid/uuid.go b/Godeps/_workspace/src/github.com/pborman/uuid/uuid.go
index 2920fae63..c4482cd87 100644
--- a/Godeps/_workspace/src/github.com/pborman/uuid/uuid.go
+++ b/Godeps/_workspace/src/github.com/pborman/uuid/uuid.go
@@ -7,6 +7,7 @@ package uuid
import (
"bytes"
"crypto/rand"
+ "encoding/hex"
"fmt"
"io"
"strings"
@@ -54,8 +55,8 @@ func Parse(s string) UUID {
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
return nil
}
- uuid := make([]byte, 16)
- for i, x := range []int{
+ var uuid [16]byte
+ for i, x := range [16]int{
0, 2, 4, 6,
9, 11,
14, 16,
@@ -67,7 +68,7 @@ func Parse(s string) UUID {
uuid[i] = v
}
}
- return uuid
+ return uuid[:]
}
// Equal returns true if uuid1 and uuid2 are equal.
@@ -78,23 +79,36 @@ func Equal(uuid1, uuid2 UUID) bool {
// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
// , or "" if uuid is invalid.
func (uuid UUID) String() string {
- if uuid == nil || len(uuid) != 16 {
+ if len(uuid) != 16 {
return ""
}
- b := []byte(uuid)
- return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x",
- b[:4], b[4:6], b[6:8], b[8:10], b[10:])
+ var buf [36]byte
+ encodeHex(buf[:], uuid)
+ return string(buf[:])
}
// URN returns the RFC 2141 URN form of uuid,
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid.
func (uuid UUID) URN() string {
- if uuid == nil || len(uuid) != 16 {
+ if len(uuid) != 16 {
return ""
}
- b := []byte(uuid)
- return fmt.Sprintf("urn:uuid:%08x-%04x-%04x-%04x-%012x",
- b[:4], b[4:6], b[6:8], b[8:10], b[10:])
+ var buf [36 + 9]byte
+ copy(buf[:], "urn:uuid:")
+ encodeHex(buf[9:], uuid)
+ return string(buf[:])
+}
+
+func encodeHex(dst []byte, uuid UUID) {
+ hex.Encode(dst[:], uuid[:4])
+ dst[8] = '-'
+ hex.Encode(dst[9:13], uuid[4:6])
+ dst[13] = '-'
+ hex.Encode(dst[14:18], uuid[6:8])
+ dst[18] = '-'
+ hex.Encode(dst[19:23], uuid[8:10])
+ dst[23] = '-'
+ hex.Encode(dst[24:], uuid[10:])
}
// Variant returns the variant encoded in uuid. It returns Invalid if
@@ -113,10 +127,9 @@ func (uuid UUID) Variant() Variant {
default:
return Reserved
}
- panic("unreachable")
}
-// Version returns the verison of uuid. It returns false if uuid is not
+// Version returns the version of uuid. It returns false if uuid is not
// valid.
func (uuid UUID) Version() (Version, bool) {
if len(uuid) != 16 {
diff --git a/Godeps/_workspace/src/github.com/pborman/uuid/uuid_test.go b/Godeps/_workspace/src/github.com/pborman/uuid/uuid_test.go
deleted file mode 100644
index 417ebeb26..000000000
--- a/Godeps/_workspace/src/github.com/pborman/uuid/uuid_test.go
+++ /dev/null
@@ -1,390 +0,0 @@
-// Copyright 2011 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package uuid
-
-import (
- "bytes"
- "fmt"
- "os"
- "strings"
- "testing"
- "time"
-)
-
-type test struct {
- in string
- version Version
- variant Variant
- isuuid bool
-}
-
-var tests = []test{
- {"f47ac10b-58cc-0372-8567-0e02b2c3d479", 0, RFC4122, true},
- {"f47ac10b-58cc-1372-8567-0e02b2c3d479", 1, RFC4122, true},
- {"f47ac10b-58cc-2372-8567-0e02b2c3d479", 2, RFC4122, true},
- {"f47ac10b-58cc-3372-8567-0e02b2c3d479", 3, RFC4122, true},
- {"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true},
- {"f47ac10b-58cc-5372-8567-0e02b2c3d479", 5, RFC4122, true},
- {"f47ac10b-58cc-6372-8567-0e02b2c3d479", 6, RFC4122, true},
- {"f47ac10b-58cc-7372-8567-0e02b2c3d479", 7, RFC4122, true},
- {"f47ac10b-58cc-8372-8567-0e02b2c3d479", 8, RFC4122, true},
- {"f47ac10b-58cc-9372-8567-0e02b2c3d479", 9, RFC4122, true},
- {"f47ac10b-58cc-a372-8567-0e02b2c3d479", 10, RFC4122, true},
- {"f47ac10b-58cc-b372-8567-0e02b2c3d479", 11, RFC4122, true},
- {"f47ac10b-58cc-c372-8567-0e02b2c3d479", 12, RFC4122, true},
- {"f47ac10b-58cc-d372-8567-0e02b2c3d479", 13, RFC4122, true},
- {"f47ac10b-58cc-e372-8567-0e02b2c3d479", 14, RFC4122, true},
- {"f47ac10b-58cc-f372-8567-0e02b2c3d479", 15, RFC4122, true},
-
- {"urn:uuid:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true},
- {"URN:UUID:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true},
- {"f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true},
- {"f47ac10b-58cc-4372-1567-0e02b2c3d479", 4, Reserved, true},
- {"f47ac10b-58cc-4372-2567-0e02b2c3d479", 4, Reserved, true},
- {"f47ac10b-58cc-4372-3567-0e02b2c3d479", 4, Reserved, true},
- {"f47ac10b-58cc-4372-4567-0e02b2c3d479", 4, Reserved, true},
- {"f47ac10b-58cc-4372-5567-0e02b2c3d479", 4, Reserved, true},
- {"f47ac10b-58cc-4372-6567-0e02b2c3d479", 4, Reserved, true},
- {"f47ac10b-58cc-4372-7567-0e02b2c3d479", 4, Reserved, true},
- {"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true},
- {"f47ac10b-58cc-4372-9567-0e02b2c3d479", 4, RFC4122, true},
- {"f47ac10b-58cc-4372-a567-0e02b2c3d479", 4, RFC4122, true},
- {"f47ac10b-58cc-4372-b567-0e02b2c3d479", 4, RFC4122, true},
- {"f47ac10b-58cc-4372-c567-0e02b2c3d479", 4, Microsoft, true},
- {"f47ac10b-58cc-4372-d567-0e02b2c3d479", 4, Microsoft, true},
- {"f47ac10b-58cc-4372-e567-0e02b2c3d479", 4, Future, true},
- {"f47ac10b-58cc-4372-f567-0e02b2c3d479", 4, Future, true},
-
- {"f47ac10b158cc-5372-a567-0e02b2c3d479", 0, Invalid, false},
- {"f47ac10b-58cc25372-a567-0e02b2c3d479", 0, Invalid, false},
- {"f47ac10b-58cc-53723a567-0e02b2c3d479", 0, Invalid, false},
- {"f47ac10b-58cc-5372-a56740e02b2c3d479", 0, Invalid, false},
- {"f47ac10b-58cc-5372-a567-0e02-2c3d479", 0, Invalid, false},
- {"g47ac10b-58cc-4372-a567-0e02b2c3d479", 0, Invalid, false},
-}
-
-var constants = []struct {
- c interface{}
- name string
-}{
- {Person, "Person"},
- {Group, "Group"},
- {Org, "Org"},
- {Invalid, "Invalid"},
- {RFC4122, "RFC4122"},
- {Reserved, "Reserved"},
- {Microsoft, "Microsoft"},
- {Future, "Future"},
- {Domain(17), "Domain17"},
- {Variant(42), "BadVariant42"},
-}
-
-func testTest(t *testing.T, in string, tt test) {
- uuid := Parse(in)
- if ok := (uuid != nil); ok != tt.isuuid {
- t.Errorf("Parse(%s) got %v expected %v\b", in, ok, tt.isuuid)
- }
- if uuid == nil {
- return
- }
-
- if v := uuid.Variant(); v != tt.variant {
- t.Errorf("Variant(%s) got %d expected %d\b", in, v, tt.variant)
- }
- if v, _ := uuid.Version(); v != tt.version {
- t.Errorf("Version(%s) got %d expected %d\b", in, v, tt.version)
- }
-}
-
-func TestUUID(t *testing.T) {
- for _, tt := range tests {
- testTest(t, tt.in, tt)
- testTest(t, strings.ToUpper(tt.in), tt)
- }
-}
-
-func TestConstants(t *testing.T) {
- for x, tt := range constants {
- v, ok := tt.c.(fmt.Stringer)
- if !ok {
- t.Errorf("%x: %v: not a stringer", x, v)
- } else if s := v.String(); s != tt.name {
- v, _ := tt.c.(int)
- t.Errorf("%x: Constant %T:%d gives %q, expected %q\n", x, tt.c, v, s, tt.name)
- }
- }
-}
-
-func TestRandomUUID(t *testing.T) {
- m := make(map[string]bool)
- for x := 1; x < 32; x++ {
- uuid := NewRandom()
- s := uuid.String()
- if m[s] {
- t.Errorf("NewRandom returned duplicated UUID %s\n", s)
- }
- m[s] = true
- if v, _ := uuid.Version(); v != 4 {
- t.Errorf("Random UUID of version %s\n", v)
- }
- if uuid.Variant() != RFC4122 {
- t.Errorf("Random UUID is variant %d\n", uuid.Variant())
- }
- }
-}
-
-func TestNew(t *testing.T) {
- m := make(map[string]bool)
- for x := 1; x < 32; x++ {
- s := New()
- if m[s] {
- t.Errorf("New returned duplicated UUID %s\n", s)
- }
- m[s] = true
- uuid := Parse(s)
- if uuid == nil {
- t.Errorf("New returned %q which does not decode\n", s)
- continue
- }
- if v, _ := uuid.Version(); v != 4 {
- t.Errorf("Random UUID of version %s\n", v)
- }
- if uuid.Variant() != RFC4122 {
- t.Errorf("Random UUID is variant %d\n", uuid.Variant())
- }
- }
-}
-
-func clockSeq(t *testing.T, uuid UUID) int {
- seq, ok := uuid.ClockSequence()
- if !ok {
- t.Fatalf("%s: invalid clock sequence\n", uuid)
- }
- return seq
-}
-
-func TestClockSeq(t *testing.T) {
- // Fake time.Now for this test to return a monotonically advancing time; restore it at end.
- defer func(orig func() time.Time) { timeNow = orig }(timeNow)
- monTime := time.Now()
- timeNow = func() time.Time {
- monTime = monTime.Add(1 * time.Second)
- return monTime
- }
-
- SetClockSequence(-1)
- uuid1 := NewUUID()
- uuid2 := NewUUID()
-
- if clockSeq(t, uuid1) != clockSeq(t, uuid2) {
- t.Errorf("clock sequence %d != %d\n", clockSeq(t, uuid1), clockSeq(t, uuid2))
- }
-
- SetClockSequence(-1)
- uuid2 = NewUUID()
-
- // Just on the very off chance we generated the same sequence
- // two times we try again.
- if clockSeq(t, uuid1) == clockSeq(t, uuid2) {
- SetClockSequence(-1)
- uuid2 = NewUUID()
- }
- if clockSeq(t, uuid1) == clockSeq(t, uuid2) {
- t.Errorf("Duplicate clock sequence %d\n", clockSeq(t, uuid1))
- }
-
- SetClockSequence(0x1234)
- uuid1 = NewUUID()
- if seq := clockSeq(t, uuid1); seq != 0x1234 {
- t.Errorf("%s: expected seq 0x1234 got 0x%04x\n", uuid1, seq)
- }
-}
-
-func TestCoding(t *testing.T) {
- text := "7d444840-9dc0-11d1-b245-5ffdce74fad2"
- urn := "urn:uuid:7d444840-9dc0-11d1-b245-5ffdce74fad2"
- data := UUID{
- 0x7d, 0x44, 0x48, 0x40,
- 0x9d, 0xc0,
- 0x11, 0xd1,
- 0xb2, 0x45,
- 0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2,
- }
- if v := data.String(); v != text {
- t.Errorf("%x: encoded to %s, expected %s\n", data, v, text)
- }
- if v := data.URN(); v != urn {
- t.Errorf("%x: urn is %s, expected %s\n", data, v, urn)
- }
-
- uuid := Parse(text)
- if !Equal(uuid, data) {
- t.Errorf("%s: decoded to %s, expected %s\n", text, uuid, data)
- }
-}
-
-func TestVersion1(t *testing.T) {
- uuid1 := NewUUID()
- uuid2 := NewUUID()
-
- if Equal(uuid1, uuid2) {
- t.Errorf("%s:duplicate uuid\n", uuid1)
- }
- if v, _ := uuid1.Version(); v != 1 {
- t.Errorf("%s: version %s expected 1\n", uuid1, v)
- }
- if v, _ := uuid2.Version(); v != 1 {
- t.Errorf("%s: version %s expected 1\n", uuid2, v)
- }
- n1 := uuid1.NodeID()
- n2 := uuid2.NodeID()
- if !bytes.Equal(n1, n2) {
- t.Errorf("Different nodes %x != %x\n", n1, n2)
- }
- t1, ok := uuid1.Time()
- if !ok {
- t.Errorf("%s: invalid time\n", uuid1)
- }
- t2, ok := uuid2.Time()
- if !ok {
- t.Errorf("%s: invalid time\n", uuid2)
- }
- q1, ok := uuid1.ClockSequence()
- if !ok {
- t.Errorf("%s: invalid clock sequence\n", uuid1)
- }
- q2, ok := uuid2.ClockSequence()
- if !ok {
- t.Errorf("%s: invalid clock sequence", uuid2)
- }
-
- switch {
- case t1 == t2 && q1 == q2:
- t.Errorf("time stopped\n")
- case t1 > t2 && q1 == q2:
- t.Errorf("time reversed\n")
- case t1 < t2 && q1 != q2:
- t.Errorf("clock sequence chaned unexpectedly\n")
- }
-}
-
-func TestNodeAndTime(t *testing.T) {
- // Time is February 5, 1998 12:30:23.136364800 AM GMT
-
- uuid := Parse("7d444840-9dc0-11d1-b245-5ffdce74fad2")
- node := []byte{0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2}
-
- ts, ok := uuid.Time()
- if ok {
- c := time.Unix(ts.UnixTime())
- want := time.Date(1998, 2, 5, 0, 30, 23, 136364800, time.UTC)
- if !c.Equal(want) {
- t.Errorf("Got time %v, want %v", c, want)
- }
- } else {
- t.Errorf("%s: bad time\n", uuid)
- }
- if !bytes.Equal(node, uuid.NodeID()) {
- t.Errorf("Expected node %v got %v\n", node, uuid.NodeID())
- }
-}
-
-func TestMD5(t *testing.T) {
- uuid := NewMD5(NameSpace_DNS, []byte("python.org")).String()
- want := "6fa459ea-ee8a-3ca4-894e-db77e160355e"
- if uuid != want {
- t.Errorf("MD5: got %q expected %q\n", uuid, want)
- }
-}
-
-func TestSHA1(t *testing.T) {
- uuid := NewSHA1(NameSpace_DNS, []byte("python.org")).String()
- want := "886313e1-3b8a-5372-9b90-0c9aee199e5d"
- if uuid != want {
- t.Errorf("SHA1: got %q expected %q\n", uuid, want)
- }
-}
-
-func TestNodeID(t *testing.T) {
- nid := []byte{1, 2, 3, 4, 5, 6}
- SetNodeInterface("")
- s := NodeInterface()
- if s == "" || s == "user" {
- t.Errorf("NodeInterface %q after SetInteface\n", s)
- }
- node1 := NodeID()
- if node1 == nil {
- t.Errorf("NodeID nil after SetNodeInterface\n", s)
- }
- SetNodeID(nid)
- s = NodeInterface()
- if s != "user" {
- t.Errorf("Expected NodeInterface %q got %q\n", "user", s)
- }
- node2 := NodeID()
- if node2 == nil {
- t.Errorf("NodeID nil after SetNodeID\n", s)
- }
- if bytes.Equal(node1, node2) {
- t.Errorf("NodeID not changed after SetNodeID\n", s)
- } else if !bytes.Equal(nid, node2) {
- t.Errorf("NodeID is %x, expected %x\n", node2, nid)
- }
-}
-
-func testDCE(t *testing.T, name string, uuid UUID, domain Domain, id uint32) {
- if uuid == nil {
- t.Errorf("%s failed\n", name)
- return
- }
- if v, _ := uuid.Version(); v != 2 {
- t.Errorf("%s: %s: expected version 2, got %s\n", name, uuid, v)
- return
- }
- if v, ok := uuid.Domain(); !ok || v != domain {
- if !ok {
- t.Errorf("%s: %d: Domain failed\n", name, uuid)
- } else {
- t.Errorf("%s: %s: expected domain %d, got %d\n", name, uuid, domain, v)
- }
- }
- if v, ok := uuid.Id(); !ok || v != id {
- if !ok {
- t.Errorf("%s: %d: Id failed\n", name, uuid)
- } else {
- t.Errorf("%s: %s: expected id %d, got %d\n", name, uuid, id, v)
- }
- }
-}
-
-func TestDCE(t *testing.T) {
- testDCE(t, "NewDCESecurity", NewDCESecurity(42, 12345678), 42, 12345678)
- testDCE(t, "NewDCEPerson", NewDCEPerson(), Person, uint32(os.Getuid()))
- testDCE(t, "NewDCEGroup", NewDCEGroup(), Group, uint32(os.Getgid()))
-}
-
-type badRand struct{}
-
-func (r badRand) Read(buf []byte) (int, error) {
- for i, _ := range buf {
- buf[i] = byte(i)
- }
- return len(buf), nil
-}
-
-func TestBadRand(t *testing.T) {
- SetRand(badRand{})
- uuid1 := New()
- uuid2 := New()
- if uuid1 != uuid2 {
- t.Errorf("execpted duplicates, got %q and %q\n", uuid1, uuid2)
- }
- SetRand(nil)
- uuid1 = New()
- uuid2 = New()
- if uuid1 == uuid2 {
- t.Errorf("unexecpted duplicates, got %q\n", uuid1)
- }
-}
diff --git a/Godeps/_workspace/src/github.com/peterh/liner/README.md b/Godeps/_workspace/src/github.com/peterh/liner/README.md
index 99027c6e2..9148b2492 100644
--- a/Godeps/_workspace/src/github.com/peterh/liner/README.md
+++ b/Godeps/_workspace/src/github.com/peterh/liner/README.md
@@ -21,8 +21,8 @@ Ctrl-A, Home | Move cursor to beginning of line
Ctrl-E, End | Move cursor to end of line
Ctrl-B, Left | Move cursor one character left
Ctrl-F, Right| Move cursor one character right
-Ctrl-Left | Move cursor to previous word
-Ctrl-Right | Move cursor to next word
+Ctrl-Left, Alt-B | Move cursor to previous word
+Ctrl-Right, Alt-F | Move cursor to next word
Ctrl-D, Del | (if line is *not* empty) Delete character under cursor
Ctrl-D | (if line *is* empty) End of File - usually quits application
Ctrl-C | Reset input (create new empty prompt)
@@ -48,13 +48,14 @@ package main
import (
"log"
"os"
+ "path/filepath"
"strings"
"github.com/peterh/liner"
)
var (
- history_fn = "/tmp/.liner_history"
+ history_fn = filepath.Join(os.TempDir(), ".liner_example_history")
names = []string{"john", "james", "mary", "nancy"}
)
@@ -62,6 +63,8 @@ func main() {
line := liner.NewLiner()
defer line.Close()
+ line.SetCtrlCAborts(true)
+
line.SetCompleter(func(line string) (c []string) {
for _, n := range names {
if strings.HasPrefix(n, strings.ToLower(line)) {
@@ -76,11 +79,13 @@ func main() {
f.Close()
}
- if name, err := line.Prompt("What is your name? "); err != nil {
- log.Print("Error reading line: ", err)
- } else {
+ if name, err := line.Prompt("What is your name? "); err == nil {
log.Print("Got: ", name)
line.AppendHistory(name)
+ } else if err == liner.ErrPromptAborted {
+ log.Print("Aborted")
+ } else {
+ log.Print("Error reading line: ", err)
}
if f, err := os.Create(history_fn); err != nil {
diff --git a/Godeps/_workspace/src/github.com/peterh/liner/common.go b/Godeps/_workspace/src/github.com/peterh/liner/common.go
index f8753a195..b6162b624 100644
--- a/Godeps/_workspace/src/github.com/peterh/liner/common.go
+++ b/Godeps/_workspace/src/github.com/peterh/liner/common.go
@@ -7,7 +7,6 @@ package liner
import (
"bufio"
- "bytes"
"container/ring"
"errors"
"fmt"
@@ -29,6 +28,10 @@ type commonState struct {
ctrlCAborts bool
r *bufio.Reader
tabStyle TabStyle
+ multiLineMode bool
+ cursorRows int
+ maxRows int
+ shouldRestart ShouldRestart
}
// TabStyle is used to select how tab completions are displayed.
@@ -174,7 +177,7 @@ func (s *State) SetCompleter(f Completer) {
return
}
s.completer = func(line string, pos int) (string, []string, string) {
- return "", f(line[:pos]), line[pos:]
+ return "", f(string([]rune(line)[:pos])), string([]rune(line)[pos:])
}
}
@@ -207,13 +210,28 @@ func (s *State) SetCtrlCAborts(aborts bool) {
s.ctrlCAborts = aborts
}
+// SetMultiLineMode sets whether line is auto-wrapped. The default is false (single line).
+func (s *State) SetMultiLineMode(mlmode bool) {
+ s.multiLineMode = mlmode
+}
+
+// ShouldRestart is passed the error generated by readNext and returns true if
+// the the read should be restarted or false if the error should be returned.
+type ShouldRestart func(err error) bool
+
+// SetShouldRestart sets the restart function that Liner will call to determine
+// whether to retry the call to, or return the error returned by, readNext.
+func (s *State) SetShouldRestart(f ShouldRestart) {
+ s.shouldRestart = f
+}
+
func (s *State) promptUnsupported(p string) (string, error) {
- if !s.inputRedirected {
+ if !s.inputRedirected || !s.terminalSupported {
fmt.Print(p)
}
linebuf, _, err := s.r.ReadLine()
if err != nil {
return "", err
}
- return string(bytes.TrimSpace(linebuf)), nil
+ return string(linebuf), nil
}
diff --git a/Godeps/_workspace/src/github.com/peterh/liner/input.go b/Godeps/_workspace/src/github.com/peterh/liner/input.go
index cf71d2bce..c80c85f69 100644
--- a/Godeps/_workspace/src/github.com/peterh/liner/input.go
+++ b/Godeps/_workspace/src/github.com/peterh/liner/input.go
@@ -44,14 +44,15 @@ func NewLiner() *State {
if m, err := TerminalMode(); err == nil {
s.origMode = *m.(*termios)
} else {
- s.terminalSupported = false
s.inputRedirected = true
}
if _, err := getMode(syscall.Stdout); err != 0 {
- s.terminalSupported = false
s.outputRedirected = true
}
- if s.terminalSupported {
+ if s.inputRedirected && s.outputRedirected {
+ s.terminalSupported = false
+ }
+ if s.terminalSupported && !s.inputRedirected && !s.outputRedirected {
mode := s.origMode
mode.Iflag &^= icrnl | inpck | istrip | ixon
mode.Cflag |= cs8
@@ -328,6 +329,12 @@ func (s *State) readNext() (interface{}, error) {
default:
return unknown, nil
}
+ case 'b':
+ s.pending = s.pending[:0] // escape code complete
+ return altB, nil
+ case 'f':
+ s.pending = s.pending[:0] // escape code complete
+ return altF, nil
case 'y':
s.pending = s.pending[:0] // escape code complete
return altY, nil
@@ -344,7 +351,7 @@ func (s *State) readNext() (interface{}, error) {
// Close returns the terminal to its previous mode
func (s *State) Close() error {
stopSignal(s.winch)
- if s.terminalSupported {
+ if !s.inputRedirected {
s.origMode.ApplyMode()
}
return nil
@@ -353,6 +360,8 @@ func (s *State) Close() error {
// TerminalSupported returns true if the current terminal supports
// line editing features, and false if liner will use the 'dumb'
// fallback for input.
+// Note that TerminalSupported does not check all factors that may
+// cause liner to not fully support the terminal (such as stdin redirection)
func TerminalSupported() bool {
bad := map[string]bool{"": true, "dumb": true, "cons25": true}
return !bad[strings.ToLower(os.Getenv("TERM"))]
diff --git a/Godeps/_workspace/src/github.com/peterh/liner/input_test.go b/Godeps/_workspace/src/github.com/peterh/liner/input_test.go
deleted file mode 100644
index e515a4894..000000000
--- a/Godeps/_workspace/src/github.com/peterh/liner/input_test.go
+++ /dev/null
@@ -1,61 +0,0 @@
-// +build !windows
-
-package liner
-
-import (
- "bufio"
- "bytes"
- "testing"
-)
-
-func (s *State) expectRune(t *testing.T, r rune) {
- item, err := s.readNext()
- if err != nil {
- t.Fatalf("Expected rune '%c', got error %s\n", r, err)
- }
- if v, ok := item.(rune); !ok {
- t.Fatalf("Expected rune '%c', got non-rune %v\n", r, v)
- } else {
- if v != r {
- t.Fatalf("Expected rune '%c', got rune '%c'\n", r, v)
- }
- }
-}
-
-func (s *State) expectAction(t *testing.T, a action) {
- item, err := s.readNext()
- if err != nil {
- t.Fatalf("Expected Action %d, got error %s\n", a, err)
- }
- if v, ok := item.(action); !ok {
- t.Fatalf("Expected Action %d, got non-Action %v\n", a, v)
- } else {
- if v != a {
- t.Fatalf("Expected Action %d, got Action %d\n", a, v)
- }
- }
-}
-
-func TestTypes(t *testing.T) {
- input := []byte{'A', 27, 'B', 27, 91, 68, 27, '[', '1', ';', '5', 'D', 'e'}
- var s State
- s.r = bufio.NewReader(bytes.NewBuffer(input))
-
- next := make(chan nexter)
- go func() {
- for {
- var n nexter
- n.r, _, n.err = s.r.ReadRune()
- next <- n
- }
- }()
- s.next = next
-
- s.expectRune(t, 'A')
- s.expectRune(t, 27)
- s.expectRune(t, 'B')
- s.expectAction(t, left)
- s.expectAction(t, wordLeft)
-
- s.expectRune(t, 'e')
-}
diff --git a/Godeps/_workspace/src/github.com/peterh/liner/input_windows.go b/Godeps/_workspace/src/github.com/peterh/liner/input_windows.go
index cc98719c1..9dcc3115c 100644
--- a/Godeps/_workspace/src/github.com/peterh/liner/input_windows.go
+++ b/Godeps/_workspace/src/github.com/peterh/liner/input_windows.go
@@ -132,6 +132,8 @@ const (
vk_f10 = 0x79
vk_f11 = 0x7a
vk_f12 = 0x7b
+ bKey = 0x42
+ fKey = 0x46
yKey = 0x59
)
@@ -178,6 +180,12 @@ func (s *State) readNext() (interface{}, error) {
if ke.VirtualKeyCode == vk_tab && ke.ControlKeyState&modKeys == shiftPressed {
s.key = shiftTab
+ } else if ke.VirtualKeyCode == bKey && (ke.ControlKeyState&modKeys == leftAltPressed ||
+ ke.ControlKeyState&modKeys == rightAltPressed) {
+ s.key = altB
+ } else if ke.VirtualKeyCode == fKey && (ke.ControlKeyState&modKeys == leftAltPressed ||
+ ke.ControlKeyState&modKeys == rightAltPressed) {
+ s.key = altF
} else if ke.VirtualKeyCode == yKey && (ke.ControlKeyState&modKeys == leftAltPressed ||
ke.ControlKeyState&modKeys == rightAltPressed) {
s.key = altY
diff --git a/Godeps/_workspace/src/github.com/peterh/liner/line.go b/Godeps/_workspace/src/github.com/peterh/liner/line.go
index a70fb59e5..95364ae56 100644
--- a/Godeps/_workspace/src/github.com/peterh/liner/line.go
+++ b/Godeps/_workspace/src/github.com/peterh/liner/line.go
@@ -37,6 +37,8 @@ const (
f10
f11
f12
+ altB
+ altF
altY
shiftTab
wordLeft
@@ -88,6 +90,14 @@ const (
)
func (s *State) refresh(prompt []rune, buf []rune, pos int) error {
+ if s.multiLineMode {
+ return s.refreshMultiLine(prompt, buf, pos)
+ } else {
+ return s.refreshSingleLine(prompt, buf, pos)
+ }
+}
+
+func (s *State) refreshSingleLine(prompt []rune, buf []rune, pos int) error {
s.cursorPos(0)
_, err := fmt.Print(string(prompt))
if err != nil {
@@ -143,6 +153,82 @@ func (s *State) refresh(prompt []rune, buf []rune, pos int) error {
return err
}
+func (s *State) refreshMultiLine(prompt []rune, buf []rune, pos int) error {
+ promptColumns := countMultiLineGlyphs(prompt, s.columns, 0)
+ totalColumns := countMultiLineGlyphs(buf, s.columns, promptColumns)
+ totalRows := (totalColumns + s.columns - 1) / s.columns
+ maxRows := s.maxRows
+ if totalRows > s.maxRows {
+ s.maxRows = totalRows
+ }
+ cursorRows := s.cursorRows
+ if cursorRows == 0 {
+ cursorRows = 1
+ }
+
+ /* First step: clear all the lines used before. To do so start by
+ * going to the last row. */
+ if maxRows-cursorRows > 0 {
+ s.moveDown(maxRows - cursorRows)
+ }
+
+ /* Now for every row clear it, go up. */
+ for i := 0; i < maxRows-1; i++ {
+ s.cursorPos(0)
+ s.eraseLine()
+ s.moveUp(1)
+ }
+
+ /* Clean the top line. */
+ s.cursorPos(0)
+ s.eraseLine()
+
+ /* Write the prompt and the current buffer content */
+ if _, err := fmt.Print(string(prompt)); err != nil {
+ return err
+ }
+ if _, err := fmt.Print(string(buf)); err != nil {
+ return err
+ }
+
+ /* If we are at the very end of the screen with our prompt, we need to
+ * emit a newline and move the prompt to the first column. */
+ cursorColumns := countMultiLineGlyphs(buf[:pos], s.columns, promptColumns)
+ if cursorColumns == totalColumns && totalColumns%s.columns == 0 {
+ s.emitNewLine()
+ s.cursorPos(0)
+ totalRows++
+ if totalRows > s.maxRows {
+ s.maxRows = totalRows
+ }
+ }
+
+ /* Move cursor to right position. */
+ cursorRows = (cursorColumns + s.columns) / s.columns
+ if s.cursorRows > 0 && totalRows-cursorRows > 0 {
+ s.moveUp(totalRows - cursorRows)
+ }
+ /* Set column. */
+ s.cursorPos(cursorColumns % s.columns)
+
+ s.cursorRows = cursorRows
+ return nil
+}
+
+func (s *State) resetMultiLine(prompt []rune, buf []rune, pos int) {
+ columns := countMultiLineGlyphs(prompt, s.columns, 0)
+ columns = countMultiLineGlyphs(buf[:pos], s.columns, columns)
+ columns += 2 // ^C
+ cursorRows := (columns + s.columns) / s.columns
+ if s.maxRows-cursorRows > 0 {
+ for i := 0; i < s.maxRows-cursorRows; i++ {
+ fmt.Println() // always moves the cursor down or scrolls the window up as needed
+ }
+ }
+ s.maxRows = 1
+ s.cursorRows = 0
+}
+
func longestCommonPrefix(strs []string) string {
if len(strs) == 0 {
return ""
@@ -179,6 +265,29 @@ func (s *State) circularTabs(items []string) func(tabDirection) (string, error)
}
}
+func calculateColumns(screenWidth int, items []string) (numColumns, numRows, maxWidth int) {
+ for _, item := range items {
+ if len(item) >= screenWidth {
+ return 1, len(items), screenWidth - 1
+ }
+ if len(item) >= maxWidth {
+ maxWidth = len(item) + 1
+ }
+ }
+
+ numColumns = screenWidth / maxWidth
+ numRows = len(items) / numColumns
+ if len(items)%numColumns > 0 {
+ numRows++
+ }
+
+ if len(items) <= numColumns {
+ maxWidth = 0
+ }
+
+ return
+}
+
func (s *State) printedTabs(items []string) func(tabDirection) (string, error) {
numTabs := 1
prefix := longestCommonPrefix(items)
@@ -190,6 +299,7 @@ func (s *State) printedTabs(items []string) func(tabDirection) (string, error) {
if numTabs == 2 {
if len(items) > 100 {
fmt.Printf("\nDisplay all %d possibilities? (y or n) ", len(items))
+ prompt:
for {
next, err := s.readNext()
if err != nil {
@@ -197,36 +307,26 @@ func (s *State) printedTabs(items []string) func(tabDirection) (string, error) {
}
if key, ok := next.(rune); ok {
- if unicode.ToLower(key) == 'n' {
+ switch key {
+ case 'n', 'N':
return prefix, nil
- } else if unicode.ToLower(key) == 'y' {
- break
+ case 'y', 'Y':
+ break prompt
+ case ctrlC, ctrlD, cr, lf:
+ s.restartPrompt()
}
}
}
}
fmt.Println("")
- maxWidth := 0
- for _, item := range items {
- if len(item) >= maxWidth {
- maxWidth = len(item) + 1
- }
- }
- numColumns := s.columns / maxWidth
- numRows := len(items) / numColumns
- if len(items)%numColumns > 0 {
- numRows++
- }
+ numColumns, numRows, maxWidth := calculateColumns(s.columns, items)
- if len(items) <= numColumns {
- maxWidth = 0
- }
for i := 0; i < numRows; i++ {
for j := 0; j < numColumns*numRows; j += numRows {
if i+j < len(items) {
if maxWidth > 0 {
- fmt.Printf("%-*s", maxWidth, items[i+j])
+ fmt.Printf("%-*.[1]*s", maxWidth, items[i+j])
} else {
fmt.Printf("%v ", items[i+j])
}
@@ -460,26 +560,20 @@ func (s *State) yank(p []rune, text []rune, pos int) ([]rune, int, interface{},
return line, pos, esc, nil
}
-// Prompt displays p, and then waits for user input. Prompt allows line editing
-// if the terminal supports it.
+// Prompt displays p and returns a line of user input, not including a trailing
+// newline character. An io.EOF error is returned if the user signals end-of-file
+// by pressing Ctrl-D. Prompt allows line editing if the terminal supports it.
func (s *State) Prompt(prompt string) (string, error) {
- if s.inputRedirected {
+ if s.inputRedirected || !s.terminalSupported {
return s.promptUnsupported(prompt)
}
if s.outputRedirected {
return "", ErrNotTerminalOutput
}
- if !s.terminalSupported {
- return s.promptUnsupported(prompt)
- }
s.historyMutex.RLock()
defer s.historyMutex.RUnlock()
- s.startPrompt()
- defer s.stopPrompt()
- s.getColumns()
-
fmt.Print(prompt)
p := []rune(prompt)
var line []rune
@@ -489,11 +583,21 @@ func (s *State) Prompt(prompt string) (string, error) {
historyPos := len(prefixHistory)
historyAction := false // used to mark history related actions
killAction := 0 // used to mark kill related actions
+
+ defer s.stopPrompt()
+
+restart:
+ s.startPrompt()
+ s.getColumns()
+
mainLoop:
for {
next, err := s.readNext()
haveNext:
if err != nil {
+ if s.shouldRestart != nil && s.shouldRestart(err) {
+ goto restart
+ }
return "", err
}
@@ -502,6 +606,9 @@ mainLoop:
case rune:
switch v {
case cr, lf:
+ if s.multiLineMode {
+ s.resetMultiLine(p, line, pos)
+ }
fmt.Println()
break mainLoop
case ctrlA: // Start of line
@@ -603,6 +710,9 @@ mainLoop:
s.refresh(p, line, pos)
case ctrlC: // reset
fmt.Println("^C")
+ if s.multiLineMode {
+ s.resetMultiLine(p, line, pos)
+ }
if s.ctrlCAborts {
return "", ErrPromptAborted
}
@@ -687,7 +797,7 @@ mainLoop:
case 0, 28, 29, 30, 31:
fmt.Print(beep)
default:
- if pos == len(line) && len(p)+len(line) < s.columns-1 {
+ if pos == len(line) && !s.multiLineMode && countGlyphs(p)+countGlyphs(line) < s.columns-1 {
line = append(line, v)
fmt.Printf("%c", v)
pos++
@@ -712,11 +822,21 @@ mainLoop:
} else {
fmt.Print(beep)
}
- case wordLeft:
+ case wordLeft, altB:
if pos > 0 {
+ var spaceHere, spaceLeft, leftKnown bool
for {
pos--
- if pos == 0 || unicode.IsSpace(line[pos-1]) {
+ if pos == 0 {
+ break
+ }
+ if leftKnown {
+ spaceHere = spaceLeft
+ } else {
+ spaceHere = unicode.IsSpace(line[pos])
+ }
+ spaceLeft, leftKnown = unicode.IsSpace(line[pos-1]), true
+ if !spaceHere && spaceLeft {
break
}
}
@@ -729,11 +849,21 @@ mainLoop:
} else {
fmt.Print(beep)
}
- case wordRight:
+ case wordRight, altF:
if pos < len(line) {
+ var spaceHere, spaceLeft, hereKnown bool
for {
pos++
- if pos == len(line) || unicode.IsSpace(line[pos]) {
+ if pos == len(line) {
+ break
+ }
+ if hereKnown {
+ spaceLeft = spaceHere
+ } else {
+ spaceLeft = unicode.IsSpace(line[pos-1])
+ }
+ spaceHere, hereKnown = unicode.IsSpace(line[pos]), true
+ if spaceHere && !spaceLeft {
break
}
}
@@ -769,6 +899,19 @@ mainLoop:
pos = 0
case end: // End of line
pos = len(line)
+ case winch: // Window change
+ if s.multiLineMode {
+ if s.maxRows-s.cursorRows > 0 {
+ s.moveDown(s.maxRows - s.cursorRows)
+ }
+ for i := 0; i < s.maxRows-1; i++ {
+ s.cursorPos(0)
+ s.eraseLine()
+ s.moveUp(1)
+ }
+ s.maxRows = 1
+ s.cursorRows = 1
+ }
}
s.refresh(p, line, pos)
}
@@ -786,18 +929,20 @@ mainLoop:
// PasswordPrompt displays p, and then waits for user input. The input typed by
// the user is not displayed in the terminal.
func (s *State) PasswordPrompt(prompt string) (string, error) {
+ if !s.terminalSupported {
+ return "", errors.New("liner: function not supported in this terminal")
+ }
if s.inputRedirected {
return s.promptUnsupported(prompt)
}
if s.outputRedirected {
return "", ErrNotTerminalOutput
}
- if !s.terminalSupported {
- return "", errors.New("liner: function not supported in this terminal")
- }
- s.startPrompt()
defer s.stopPrompt()
+
+restart:
+ s.startPrompt()
s.getColumns()
fmt.Print(prompt)
@@ -809,6 +954,9 @@ mainLoop:
for {
next, err := s.readNext()
if err != nil {
+ if s.shouldRestart != nil && s.shouldRestart(err) {
+ goto restart
+ }
return "", err
}
@@ -816,6 +964,9 @@ mainLoop:
case rune:
switch v {
case cr, lf:
+ if s.multiLineMode {
+ s.resetMultiLine(p, line, pos)
+ }
fmt.Println()
break mainLoop
case ctrlD: // del
@@ -840,6 +991,9 @@ mainLoop:
}
case ctrlC:
fmt.Println("^C")
+ if s.multiLineMode {
+ s.resetMultiLine(p, line, pos)
+ }
if s.ctrlCAborts {
return "", ErrPromptAborted
}
diff --git a/Godeps/_workspace/src/github.com/peterh/liner/line_test.go b/Godeps/_workspace/src/github.com/peterh/liner/line_test.go
deleted file mode 100644
index 727da6ce7..000000000
--- a/Godeps/_workspace/src/github.com/peterh/liner/line_test.go
+++ /dev/null
@@ -1,90 +0,0 @@
-package liner
-
-import (
- "bytes"
- "strings"
- "testing"
-)
-
-func TestAppend(t *testing.T) {
- var s State
- s.AppendHistory("foo")
- s.AppendHistory("bar")
-
- var out bytes.Buffer
- num, err := s.WriteHistory(&out)
- if err != nil {
- t.Fatal("Unexpected error writing history", err)
- }
- if num != 2 {
- t.Fatalf("Expected 2 history entries, got %d", num)
- }
-
- s.AppendHistory("baz")
- num, err = s.WriteHistory(&out)
- if err != nil {
- t.Fatal("Unexpected error writing history", err)
- }
- if num != 3 {
- t.Fatalf("Expected 3 history entries, got %d", num)
- }
-
- s.AppendHistory("baz")
- num, err = s.WriteHistory(&out)
- if err != nil {
- t.Fatal("Unexpected error writing history", err)
- }
- if num != 3 {
- t.Fatalf("Expected 3 history entries after duplicate append, got %d", num)
- }
-
- s.AppendHistory("baz")
-
-}
-
-func TestHistory(t *testing.T) {
- input := `foo
-bar
-baz
-quux
-dingle`
-
- var s State
- num, err := s.ReadHistory(strings.NewReader(input))
- if err != nil {
- t.Fatal("Unexpected error reading history", err)
- }
- if num != 5 {
- t.Fatal("Wrong number of history entries read")
- }
-
- var out bytes.Buffer
- num, err = s.WriteHistory(&out)
- if err != nil {
- t.Fatal("Unexpected error writing history", err)
- }
- if num != 5 {
- t.Fatal("Wrong number of history entries written")
- }
- if strings.TrimSpace(out.String()) != input {
- t.Fatal("Round-trip failure")
- }
-
- // Test reading with a trailing newline present
- var s2 State
- num, err = s2.ReadHistory(&out)
- if err != nil {
- t.Fatal("Unexpected error reading history the 2nd time", err)
- }
- if num != 5 {
- t.Fatal("Wrong number of history entries read the 2nd time")
- }
-
- num, err = s.ReadHistory(strings.NewReader(input + "\n\xff"))
- if err == nil {
- t.Fatal("Unexpected success reading corrupted history", err)
- }
- if num != 5 {
- t.Fatal("Wrong number of history entries read the 3rd time")
- }
-}
diff --git a/Godeps/_workspace/src/github.com/peterh/liner/output.go b/Godeps/_workspace/src/github.com/peterh/liner/output.go
index e91f4ea81..049273b53 100644
--- a/Godeps/_workspace/src/github.com/peterh/liner/output.go
+++ b/Godeps/_workspace/src/github.com/peterh/liner/output.go
@@ -31,6 +31,18 @@ func (s *State) eraseScreen() {
fmt.Print("\x1b[H\x1b[2J")
}
+func (s *State) moveUp(lines int) {
+ fmt.Printf("\x1b[%dA", lines)
+}
+
+func (s *State) moveDown(lines int) {
+ fmt.Printf("\x1b[%dB", lines)
+}
+
+func (s *State) emitNewLine() {
+ fmt.Print("\n")
+}
+
type winSize struct {
row, col uint16
xpixel, ypixel uint16
diff --git a/Godeps/_workspace/src/github.com/peterh/liner/output_windows.go b/Godeps/_workspace/src/github.com/peterh/liner/output_windows.go
index 27ae55a14..45cd978c9 100644
--- a/Godeps/_workspace/src/github.com/peterh/liner/output_windows.go
+++ b/Godeps/_workspace/src/github.com/peterh/liner/output_windows.go
@@ -47,6 +47,24 @@ func (s *State) eraseScreen() {
procSetConsoleCursorPosition.Call(uintptr(s.hOut), 0)
}
+func (s *State) moveUp(lines int) {
+ var sbi consoleScreenBufferInfo
+ procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi)))
+ procSetConsoleCursorPosition.Call(uintptr(s.hOut),
+ uintptr(int(sbi.dwCursorPosition.x)&0xFFFF|(int(sbi.dwCursorPosition.y)-lines)<<16))
+}
+
+func (s *State) moveDown(lines int) {
+ var sbi consoleScreenBufferInfo
+ procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi)))
+ procSetConsoleCursorPosition.Call(uintptr(s.hOut),
+ uintptr(int(sbi.dwCursorPosition.x)&0xFFFF|(int(sbi.dwCursorPosition.y)+lines)<<16))
+}
+
+func (s *State) emitNewLine() {
+ // windows doesn't need to omit a new line
+}
+
func (s *State) getColumns() {
var sbi consoleScreenBufferInfo
procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi)))
diff --git a/Godeps/_workspace/src/github.com/peterh/liner/prefix_test.go b/Godeps/_workspace/src/github.com/peterh/liner/prefix_test.go
deleted file mode 100644
index c826d6c3b..000000000
--- a/Godeps/_workspace/src/github.com/peterh/liner/prefix_test.go
+++ /dev/null
@@ -1,37 +0,0 @@
-// +build windows linux darwin openbsd freebsd netbsd
-
-package liner
-
-import "testing"
-
-type testItem struct {
- list []string
- prefix string
-}
-
-func TestPrefix(t *testing.T) {
- list := []testItem{
- {[]string{"food", "foot"}, "foo"},
- {[]string{"foo", "foot"}, "foo"},
- {[]string{"food", "foo"}, "foo"},
- {[]string{"food", "foe", "foot"}, "fo"},
- {[]string{"food", "foot", "barbeque"}, ""},
- {[]string{"cafeteria", "café"}, "caf"},
- {[]string{"cafe", "café"}, "caf"},
- {[]string{"cafè", "café"}, "caf"},
- {[]string{"cafés", "café"}, "café"},
- {[]string{"áéíóú", "áéíóú"}, "áéíóú"},
- {[]string{"éclairs", "éclairs"}, "éclairs"},
- {[]string{"éclairs are the best", "éclairs are great", "éclairs"}, "éclairs"},
- {[]string{"éclair", "éclairs"}, "éclair"},
- {[]string{"éclairs", "éclair"}, "éclair"},
- {[]string{"éclair", "élan"}, "é"},
- }
-
- for _, test := range list {
- lcp := longestCommonPrefix(test.list)
- if lcp != test.prefix {
- t.Errorf("%s != %s for %+v", lcp, test.prefix, test.list)
- }
- }
-}
diff --git a/Godeps/_workspace/src/github.com/peterh/liner/race_test.go b/Godeps/_workspace/src/github.com/peterh/liner/race_test.go
deleted file mode 100644
index e320849c7..000000000
--- a/Godeps/_workspace/src/github.com/peterh/liner/race_test.go
+++ /dev/null
@@ -1,44 +0,0 @@
-// +build race
-
-package liner
-
-import (
- "io/ioutil"
- "os"
- "sync"
- "testing"
-)
-
-func TestWriteHistory(t *testing.T) {
- oldout := os.Stdout
- defer func() { os.Stdout = oldout }()
- oldin := os.Stdout
- defer func() { os.Stdin = oldin }()
-
- newinr, newinw, err := os.Pipe()
- if err != nil {
- t.Fatal(err)
- }
- os.Stdin = newinr
- newoutr, newoutw, err := os.Pipe()
- if err != nil {
- t.Fatal(err)
- }
- defer newoutr.Close()
- os.Stdout = newoutw
-
- var wait sync.WaitGroup
- wait.Add(1)
- s := NewLiner()
- go func() {
- s.AppendHistory("foo")
- s.AppendHistory("bar")
- s.Prompt("")
- wait.Done()
- }()
-
- s.WriteHistory(ioutil.Discard)
-
- newinw.Close()
- wait.Wait()
-}
diff --git a/Godeps/_workspace/src/github.com/peterh/liner/width.go b/Godeps/_workspace/src/github.com/peterh/liner/width.go
index 02cfb5e1b..d8984aae9 100644
--- a/Godeps/_workspace/src/github.com/peterh/liner/width.go
+++ b/Godeps/_workspace/src/github.com/peterh/liner/width.go
@@ -13,10 +13,42 @@ var zeroWidth = []*unicode.RangeTable{
unicode.Cf,
}
+var doubleWidth = []*unicode.RangeTable{
+ unicode.Han,
+ unicode.Hangul,
+ unicode.Hiragana,
+ unicode.Katakana,
+}
+
+// countGlyphs considers zero-width characters to be zero glyphs wide,
+// and members of Chinese, Japanese, and Korean scripts to be 2 glyphs wide.
func countGlyphs(s []rune) int {
n := 0
for _, r := range s {
- if !unicode.IsOneOf(zeroWidth, r) {
+ switch {
+ case unicode.IsOneOf(zeroWidth, r):
+ case unicode.IsOneOf(doubleWidth, r):
+ n += 2
+ default:
+ n++
+ }
+ }
+ return n
+}
+
+func countMultiLineGlyphs(s []rune, columns int, start int) int {
+ n := start
+ for _, r := range s {
+ switch {
+ case unicode.IsOneOf(zeroWidth, r):
+ case unicode.IsOneOf(doubleWidth, r):
+ n += 2
+ // no room for a 2-glyphs-wide char in the ending
+ // so skip a column and display it at the beginning
+ if n%columns == 1 {
+ n++
+ }
+ default:
n++
}
}
diff --git a/Godeps/_workspace/src/github.com/peterh/liner/width_test.go b/Godeps/_workspace/src/github.com/peterh/liner/width_test.go
deleted file mode 100644
index 134920a4b..000000000
--- a/Godeps/_workspace/src/github.com/peterh/liner/width_test.go
+++ /dev/null
@@ -1,87 +0,0 @@
-package liner
-
-import (
- "strconv"
- "testing"
-)
-
-func accent(in []rune) []rune {
- var out []rune
- for _, r := range in {
- out = append(out, r)
- out = append(out, '\u0301')
- }
- return out
-}
-
-var testString = []rune("query")
-
-func TestCountGlyphs(t *testing.T) {
- count := countGlyphs(testString)
- if count != len(testString) {
- t.Errorf("ASCII count incorrect. %d != %d", count, len(testString))
- }
- count = countGlyphs(accent(testString))
- if count != len(testString) {
- t.Errorf("Accent count incorrect. %d != %d", count, len(testString))
- }
-}
-
-func compare(a, b []rune, name string, t *testing.T) {
- if len(a) != len(b) {
- t.Errorf(`"%s" != "%s" in %s"`, string(a), string(b), name)
- return
- }
- for i := range a {
- if a[i] != b[i] {
- t.Errorf(`"%s" != "%s" in %s"`, string(a), string(b), name)
- return
- }
- }
-}
-
-func TestPrefixGlyphs(t *testing.T) {
- for i := 0; i <= len(testString); i++ {
- iter := strconv.Itoa(i)
- out := getPrefixGlyphs(testString, i)
- compare(out, testString[:i], "ascii prefix "+iter, t)
- out = getPrefixGlyphs(accent(testString), i)
- compare(out, accent(testString[:i]), "accent prefix "+iter, t)
- }
- out := getPrefixGlyphs(testString, 999)
- compare(out, testString, "ascii prefix overflow", t)
- out = getPrefixGlyphs(accent(testString), 999)
- compare(out, accent(testString), "accent prefix overflow", t)
-
- out = getPrefixGlyphs(testString, -3)
- if len(out) != 0 {
- t.Error("ascii prefix negative")
- }
- out = getPrefixGlyphs(accent(testString), -3)
- if len(out) != 0 {
- t.Error("accent prefix negative")
- }
-}
-
-func TestSuffixGlyphs(t *testing.T) {
- for i := 0; i <= len(testString); i++ {
- iter := strconv.Itoa(i)
- out := getSuffixGlyphs(testString, i)
- compare(out, testString[len(testString)-i:], "ascii suffix "+iter, t)
- out = getSuffixGlyphs(accent(testString), i)
- compare(out, accent(testString[len(testString)-i:]), "accent suffix "+iter, t)
- }
- out := getSuffixGlyphs(testString, 999)
- compare(out, testString, "ascii suffix overflow", t)
- out = getSuffixGlyphs(accent(testString), 999)
- compare(out, accent(testString), "accent suffix overflow", t)
-
- out = getSuffixGlyphs(testString, -3)
- if len(out) != 0 {
- t.Error("ascii suffix negative")
- }
- out = getSuffixGlyphs(accent(testString), -3)
- if len(out) != 0 {
- t.Error("accent suffix negative")
- }
-}
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/.travis.yml b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/.travis.yml
new file mode 100644
index 000000000..20aa5d042
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/.travis.yml
@@ -0,0 +1,14 @@
+language: go
+
+go:
+ - 1.2
+ - 1.3
+ - 1.4
+ - 1.5
+
+script:
+ - ./validate.sh
+
+# this should give us faster builds according to
+# http://docs.travis-ci.com/user/migrating-from-legacy/
+sudo: false
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/README.md b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/README.md
index e0091a4bd..66ba9cab5 100644
--- a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/README.md
+++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/README.md
@@ -1,7 +1,9 @@
go-metrics
==========
-Go port of Coda Hale's Metrics library: <https://github.com/codahale/metrics>.
+![travis build status](https://travis-ci.org/rcrowley/go-metrics.svg?branch=master)
+
+Go port of Coda Hale's Metrics library: <https://github.com/dropwizard/metrics>.
Documentation: <http://godoc.org/github.com/rcrowley/go-metrics>.
@@ -37,7 +39,7 @@ t.Update(47)
Periodically log every metric in human-readable form to standard error:
```go
-go metrics.Log(metrics.DefaultRegistry, 60e9, log.New(os.Stderr, "metrics: ", log.Lmicroseconds))
+go metrics.Log(metrics.DefaultRegistry, 5 * time.Second, log.New(os.Stderr, "metrics: ", log.Lmicroseconds))
```
Periodically log every metric in slightly-more-parseable form to syslog:
@@ -47,15 +49,23 @@ w, _ := syslog.Dial("unixgram", "/dev/log", syslog.LOG_INFO, "metrics")
go metrics.Syslog(metrics.DefaultRegistry, 60e9, w)
```
-Periodically emit every metric to Graphite:
+Periodically emit every metric to Graphite using the [Graphite client](https://github.com/cyberdelia/go-metrics-graphite):
```go
+
+import "github.com/cyberdelia/go-metrics-graphite"
+
addr, _ := net.ResolveTCPAddr("tcp", "127.0.0.1:2003")
-go metrics.Graphite(metrics.DefaultRegistry, 10e9, "metrics", addr)
+go graphite.Graphite(metrics.DefaultRegistry, 10e9, "metrics", addr)
```
Periodically emit every metric into InfluxDB:
+**NOTE:** this has been pulled out of the library due to constant fluctuations
+in the InfluxDB API. In fact, all client libraries are on their way out. see
+issues [#121](https://github.com/rcrowley/go-metrics/issues/121) and
+[#124](https://github.com/rcrowley/go-metrics/issues/124) for progress and details.
+
```go
import "github.com/rcrowley/go-metrics/influxdb"
@@ -67,17 +77,20 @@ go influxdb.Influxdb(metrics.DefaultRegistry, 10e9, &influxdb.Config{
})
```
-Periodically upload every metric to Librato:
+Periodically upload every metric to Librato using the [Librato client](https://github.com/mihasya/go-metrics-librato):
+
+**Note**: the client included with this repository under the `librato` package
+has been deprecated and moved to the repository linked above.
```go
-import "github.com/rcrowley/go-metrics/librato"
+import "github.com/mihasya/go-metrics-librato"
go librato.Librato(metrics.DefaultRegistry,
10e9, // interval
"example@example.com", // account owner email address
"token", // Librato API token
"hostname", // source
- []float64{0.95}, // precentiles to send
+ []float64{0.95}, // percentiles to send
time.Millisecond, // time unit
)
```
@@ -90,6 +103,19 @@ import "github.com/rcrowley/go-metrics/stathat"
go stathat.Stathat(metrics.DefaultRegistry, 10e9, "example@example.com")
```
+Maintain all metrics along with expvars at `/debug/metrics`:
+
+This uses the same mechanism as [the official expvar](http://golang.org/pkg/expvar/)
+but exposed under `/debug/metrics`, which shows a json representation of all your usual expvars
+as well as all your go-metrics.
+
+
+```go
+import "github.com/rcrowley/go-metrics/exp"
+
+exp.Exp(metrics.DefaultRegistry)
+```
+
Installation
------------
@@ -102,3 +128,12 @@ StatHat support additionally requires their Go client:
```sh
go get github.com/stathat/go
```
+
+Publishing Metrics
+------------------
+
+Clients are available for the following destinations:
+
+* Librato - [https://github.com/mihasya/go-metrics-librato](https://github.com/mihasya/go-metrics-librato)
+* Graphite - [https://github.com/cyberdelia/go-metrics-graphite](https://github.com/cyberdelia/go-metrics-graphite)
+* InfluxDB - [https://github.com/vrischmann/go-metrics-influxdb](https://github.com/vrischmann/go-metrics-influxdb)
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/counter_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/counter_test.go
deleted file mode 100644
index dfb03b4e8..000000000
--- a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/counter_test.go
+++ /dev/null
@@ -1,77 +0,0 @@
-package metrics
-
-import "testing"
-
-func BenchmarkCounter(b *testing.B) {
- c := NewCounter()
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- c.Inc(1)
- }
-}
-
-func TestCounterClear(t *testing.T) {
- c := NewCounter()
- c.Inc(1)
- c.Clear()
- if count := c.Count(); 0 != count {
- t.Errorf("c.Count(): 0 != %v\n", count)
- }
-}
-
-func TestCounterDec1(t *testing.T) {
- c := NewCounter()
- c.Dec(1)
- if count := c.Count(); -1 != count {
- t.Errorf("c.Count(): -1 != %v\n", count)
- }
-}
-
-func TestCounterDec2(t *testing.T) {
- c := NewCounter()
- c.Dec(2)
- if count := c.Count(); -2 != count {
- t.Errorf("c.Count(): -2 != %v\n", count)
- }
-}
-
-func TestCounterInc1(t *testing.T) {
- c := NewCounter()
- c.Inc(1)
- if count := c.Count(); 1 != count {
- t.Errorf("c.Count(): 1 != %v\n", count)
- }
-}
-
-func TestCounterInc2(t *testing.T) {
- c := NewCounter()
- c.Inc(2)
- if count := c.Count(); 2 != count {
- t.Errorf("c.Count(): 2 != %v\n", count)
- }
-}
-
-func TestCounterSnapshot(t *testing.T) {
- c := NewCounter()
- c.Inc(1)
- snapshot := c.Snapshot()
- c.Inc(1)
- if count := snapshot.Count(); 1 != count {
- t.Errorf("c.Count(): 1 != %v\n", count)
- }
-}
-
-func TestCounterZero(t *testing.T) {
- c := NewCounter()
- if count := c.Count(); 0 != count {
- t.Errorf("c.Count(): 0 != %v\n", count)
- }
-}
-
-func TestGetOrRegisterCounter(t *testing.T) {
- r := NewRegistry()
- NewRegisteredCounter("foo", r).Inc(47)
- if c := GetOrRegisterCounter("foo", r); 47 != c.Count() {
- t.Fatal(c)
- }
-}
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/debug_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/debug_test.go
deleted file mode 100644
index 07eb86784..000000000
--- a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/debug_test.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package metrics
-
-import (
- "runtime"
- "runtime/debug"
- "testing"
- "time"
-)
-
-func BenchmarkDebugGCStats(b *testing.B) {
- r := NewRegistry()
- RegisterDebugGCStats(r)
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- CaptureDebugGCStatsOnce(r)
- }
-}
-
-func TestDebugGCStatsBlocking(t *testing.T) {
- if g := runtime.GOMAXPROCS(0); g < 2 {
- t.Skipf("skipping TestDebugGCMemStatsBlocking with GOMAXPROCS=%d\n", g)
- return
- }
- ch := make(chan int)
- go testDebugGCStatsBlocking(ch)
- var gcStats debug.GCStats
- t0 := time.Now()
- debug.ReadGCStats(&gcStats)
- t1 := time.Now()
- t.Log("i++ during debug.ReadGCStats:", <-ch)
- go testDebugGCStatsBlocking(ch)
- d := t1.Sub(t0)
- t.Log(d)
- time.Sleep(d)
- t.Log("i++ during time.Sleep:", <-ch)
-}
-
-func testDebugGCStatsBlocking(ch chan int) {
- i := 0
- for {
- select {
- case ch <- i:
- return
- default:
- i++
- }
- }
-}
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/ewma.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/ewma.go
index 7c152a174..694a1d033 100644
--- a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/ewma.go
+++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/ewma.go
@@ -77,7 +77,7 @@ func (NilEWMA) Update(n int64) {}
// of uncounted events and processes them on each tick. It uses the
// sync/atomic package to manage uncounted events.
type StandardEWMA struct {
- uncounted int64 // /!\ this should be the first member to ensure 64-bit alignment
+ uncounted int64 // /!\ this should be the first member to ensure 64-bit alignment
alpha float64
rate float64
init bool
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/ewma_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/ewma_test.go
deleted file mode 100644
index 0430fbd24..000000000
--- a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/ewma_test.go
+++ /dev/null
@@ -1,225 +0,0 @@
-package metrics
-
-import "testing"
-
-func BenchmarkEWMA(b *testing.B) {
- a := NewEWMA1()
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- a.Update(1)
- a.Tick()
- }
-}
-
-func TestEWMA1(t *testing.T) {
- a := NewEWMA1()
- a.Update(3)
- a.Tick()
- if rate := a.Rate(); 0.6 != rate {
- t.Errorf("initial a.Rate(): 0.6 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.22072766470286553 != rate {
- t.Errorf("1 minute a.Rate(): 0.22072766470286553 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.08120116994196772 != rate {
- t.Errorf("2 minute a.Rate(): 0.08120116994196772 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.029872241020718428 != rate {
- t.Errorf("3 minute a.Rate(): 0.029872241020718428 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.01098938333324054 != rate {
- t.Errorf("4 minute a.Rate(): 0.01098938333324054 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.004042768199451294 != rate {
- t.Errorf("5 minute a.Rate(): 0.004042768199451294 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.0014872513059998212 != rate {
- t.Errorf("6 minute a.Rate(): 0.0014872513059998212 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.0005471291793327122 != rate {
- t.Errorf("7 minute a.Rate(): 0.0005471291793327122 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.00020127757674150815 != rate {
- t.Errorf("8 minute a.Rate(): 0.00020127757674150815 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 7.404588245200814e-05 != rate {
- t.Errorf("9 minute a.Rate(): 7.404588245200814e-05 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 2.7239957857491083e-05 != rate {
- t.Errorf("10 minute a.Rate(): 2.7239957857491083e-05 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 1.0021020474147462e-05 != rate {
- t.Errorf("11 minute a.Rate(): 1.0021020474147462e-05 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 3.6865274119969525e-06 != rate {
- t.Errorf("12 minute a.Rate(): 3.6865274119969525e-06 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 1.3561976441886433e-06 != rate {
- t.Errorf("13 minute a.Rate(): 1.3561976441886433e-06 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 4.989172314621449e-07 != rate {
- t.Errorf("14 minute a.Rate(): 4.989172314621449e-07 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 1.8354139230109722e-07 != rate {
- t.Errorf("15 minute a.Rate(): 1.8354139230109722e-07 != %v\n", rate)
- }
-}
-
-func TestEWMA5(t *testing.T) {
- a := NewEWMA5()
- a.Update(3)
- a.Tick()
- if rate := a.Rate(); 0.6 != rate {
- t.Errorf("initial a.Rate(): 0.6 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.49123845184678905 != rate {
- t.Errorf("1 minute a.Rate(): 0.49123845184678905 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.4021920276213837 != rate {
- t.Errorf("2 minute a.Rate(): 0.4021920276213837 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.32928698165641596 != rate {
- t.Errorf("3 minute a.Rate(): 0.32928698165641596 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.269597378470333 != rate {
- t.Errorf("4 minute a.Rate(): 0.269597378470333 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.2207276647028654 != rate {
- t.Errorf("5 minute a.Rate(): 0.2207276647028654 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.18071652714732128 != rate {
- t.Errorf("6 minute a.Rate(): 0.18071652714732128 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.14795817836496392 != rate {
- t.Errorf("7 minute a.Rate(): 0.14795817836496392 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.12113791079679326 != rate {
- t.Errorf("8 minute a.Rate(): 0.12113791079679326 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.09917933293295193 != rate {
- t.Errorf("9 minute a.Rate(): 0.09917933293295193 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.08120116994196763 != rate {
- t.Errorf("10 minute a.Rate(): 0.08120116994196763 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.06648189501740036 != rate {
- t.Errorf("11 minute a.Rate(): 0.06648189501740036 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.05443077197364752 != rate {
- t.Errorf("12 minute a.Rate(): 0.05443077197364752 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.04456414692860035 != rate {
- t.Errorf("13 minute a.Rate(): 0.04456414692860035 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.03648603757513079 != rate {
- t.Errorf("14 minute a.Rate(): 0.03648603757513079 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.0298722410207183831020718428 != rate {
- t.Errorf("15 minute a.Rate(): 0.0298722410207183831020718428 != %v\n", rate)
- }
-}
-
-func TestEWMA15(t *testing.T) {
- a := NewEWMA15()
- a.Update(3)
- a.Tick()
- if rate := a.Rate(); 0.6 != rate {
- t.Errorf("initial a.Rate(): 0.6 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.5613041910189706 != rate {
- t.Errorf("1 minute a.Rate(): 0.5613041910189706 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.5251039914257684 != rate {
- t.Errorf("2 minute a.Rate(): 0.5251039914257684 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.4912384518467888184678905 != rate {
- t.Errorf("3 minute a.Rate(): 0.4912384518467888184678905 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.459557003018789 != rate {
- t.Errorf("4 minute a.Rate(): 0.459557003018789 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.4299187863442732 != rate {
- t.Errorf("5 minute a.Rate(): 0.4299187863442732 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.4021920276213831 != rate {
- t.Errorf("6 minute a.Rate(): 0.4021920276213831 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.37625345116383313 != rate {
- t.Errorf("7 minute a.Rate(): 0.37625345116383313 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.3519877317060185 != rate {
- t.Errorf("8 minute a.Rate(): 0.3519877317060185 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.3292869816564153165641596 != rate {
- t.Errorf("9 minute a.Rate(): 0.3292869816564153165641596 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.3080502714195546 != rate {
- t.Errorf("10 minute a.Rate(): 0.3080502714195546 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.2881831806538789 != rate {
- t.Errorf("11 minute a.Rate(): 0.2881831806538789 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.26959737847033216 != rate {
- t.Errorf("12 minute a.Rate(): 0.26959737847033216 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.2522102307052083 != rate {
- t.Errorf("13 minute a.Rate(): 0.2522102307052083 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.23594443252115815 != rate {
- t.Errorf("14 minute a.Rate(): 0.23594443252115815 != %v\n", rate)
- }
- elapseMinute(a)
- if rate := a.Rate(); 0.2207276647028646247028654470286553 != rate {
- t.Errorf("15 minute a.Rate(): 0.2207276647028646247028654470286553 != %v\n", rate)
- }
-}
-
-func elapseMinute(a EWMA) {
- for i := 0; i < 12; i++ {
- a.Tick()
- }
-}
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/exp/exp.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/exp/exp.go
new file mode 100644
index 000000000..09a496f11
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/exp/exp.go
@@ -0,0 +1,148 @@
+// Hook go-metrics into expvar
+// on any /debug/metrics request, load all vars from the registry into expvar, and execute regular expvar handler
+package exp
+
+import (
+ "expvar"
+ "fmt"
+ "github.com/rcrowley/go-metrics"
+ "net/http"
+ "sync"
+)
+
+type exp struct {
+ expvarLock sync.Mutex // expvar panics if you try to register the same var twice, so we must probe it safely
+ registry metrics.Registry
+}
+
+func (exp *exp) expHandler(w http.ResponseWriter, r *http.Request) {
+ // load our variables into expvar
+ exp.syncToExpvar()
+
+ // now just run the official expvar handler code (which is not publicly callable, so pasted inline)
+ w.Header().Set("Content-Type", "application/json; charset=utf-8")
+ fmt.Fprintf(w, "{\n")
+ first := true
+ expvar.Do(func(kv expvar.KeyValue) {
+ if !first {
+ fmt.Fprintf(w, ",\n")
+ }
+ first = false
+ fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
+ })
+ fmt.Fprintf(w, "\n}\n")
+}
+
+func Exp(r metrics.Registry) {
+ e := exp{sync.Mutex{}, r}
+ // this would cause a panic:
+ // panic: http: multiple registrations for /debug/vars
+ // http.HandleFunc("/debug/vars", e.expHandler)
+ // haven't found an elegant way, so just use a different endpoint
+ http.HandleFunc("/debug/metrics", e.expHandler)
+}
+
+func (exp *exp) getInt(name string) *expvar.Int {
+ var v *expvar.Int
+ exp.expvarLock.Lock()
+ p := expvar.Get(name)
+ if p != nil {
+ v = p.(*expvar.Int)
+ } else {
+ v = new(expvar.Int)
+ expvar.Publish(name, v)
+ }
+ exp.expvarLock.Unlock()
+ return v
+}
+
+func (exp *exp) getFloat(name string) *expvar.Float {
+ var v *expvar.Float
+ exp.expvarLock.Lock()
+ p := expvar.Get(name)
+ if p != nil {
+ v = p.(*expvar.Float)
+ } else {
+ v = new(expvar.Float)
+ expvar.Publish(name, v)
+ }
+ exp.expvarLock.Unlock()
+ return v
+}
+
+func (exp *exp) publishCounter(name string, metric metrics.Counter) {
+ v := exp.getInt(name)
+ v.Set(metric.Count())
+}
+
+func (exp *exp) publishGauge(name string, metric metrics.Gauge) {
+ v := exp.getInt(name)
+ v.Set(metric.Value())
+}
+func (exp *exp) publishGaugeFloat64(name string, metric metrics.GaugeFloat64) {
+ exp.getFloat(name).Set(metric.Value())
+}
+
+func (exp *exp) publishHistogram(name string, metric metrics.Histogram) {
+ h := metric.Snapshot()
+ ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
+ exp.getInt(name + ".count").Set(h.Count())
+ exp.getFloat(name + ".min").Set(float64(h.Min()))
+ exp.getFloat(name + ".max").Set(float64(h.Max()))
+ exp.getFloat(name + ".mean").Set(float64(h.Mean()))
+ exp.getFloat(name + ".std-dev").Set(float64(h.StdDev()))
+ exp.getFloat(name + ".50-percentile").Set(float64(ps[0]))
+ exp.getFloat(name + ".75-percentile").Set(float64(ps[1]))
+ exp.getFloat(name + ".95-percentile").Set(float64(ps[2]))
+ exp.getFloat(name + ".99-percentile").Set(float64(ps[3]))
+ exp.getFloat(name + ".999-percentile").Set(float64(ps[4]))
+}
+
+func (exp *exp) publishMeter(name string, metric metrics.Meter) {
+ m := metric.Snapshot()
+ exp.getInt(name + ".count").Set(m.Count())
+ exp.getFloat(name + ".one-minute").Set(float64(m.Rate1()))
+ exp.getFloat(name + ".five-minute").Set(float64(m.Rate5()))
+ exp.getFloat(name + ".fifteen-minute").Set(float64((m.Rate15())))
+ exp.getFloat(name + ".mean").Set(float64(m.RateMean()))
+}
+
+func (exp *exp) publishTimer(name string, metric metrics.Timer) {
+ t := metric.Snapshot()
+ ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
+ exp.getInt(name + ".count").Set(t.Count())
+ exp.getFloat(name + ".min").Set(float64(t.Min()))
+ exp.getFloat(name + ".max").Set(float64(t.Max()))
+ exp.getFloat(name + ".mean").Set(float64(t.Mean()))
+ exp.getFloat(name + ".std-dev").Set(float64(t.StdDev()))
+ exp.getFloat(name + ".50-percentile").Set(float64(ps[0]))
+ exp.getFloat(name + ".75-percentile").Set(float64(ps[1]))
+ exp.getFloat(name + ".95-percentile").Set(float64(ps[2]))
+ exp.getFloat(name + ".99-percentile").Set(float64(ps[3]))
+ exp.getFloat(name + ".999-percentile").Set(float64(ps[4]))
+ exp.getFloat(name + ".one-minute").Set(float64(t.Rate1()))
+ exp.getFloat(name + ".five-minute").Set(float64(t.Rate5()))
+ exp.getFloat(name + ".fifteen-minute").Set(float64((t.Rate15())))
+ exp.getFloat(name + ".mean-rate").Set(float64(t.RateMean()))
+}
+
+func (exp *exp) syncToExpvar() {
+ exp.registry.Each(func(name string, i interface{}) {
+ switch i.(type) {
+ case metrics.Counter:
+ exp.publishCounter(name, i.(metrics.Counter))
+ case metrics.Gauge:
+ exp.publishGauge(name, i.(metrics.Gauge))
+ case metrics.GaugeFloat64:
+ exp.publishGaugeFloat64(name, i.(metrics.GaugeFloat64))
+ case metrics.Histogram:
+ exp.publishHistogram(name, i.(metrics.Histogram))
+ case metrics.Meter:
+ exp.publishMeter(name, i.(metrics.Meter))
+ case metrics.Timer:
+ exp.publishTimer(name, i.(metrics.Timer))
+ default:
+ panic(fmt.Sprintf("unsupported type for '%s': %T", name, i))
+ }
+ })
+}
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/gauge_float64_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/gauge_float64_test.go
deleted file mode 100644
index 5d0aae271..000000000
--- a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/gauge_float64_test.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package metrics
-
-import "testing"
-
-func BenchmarkGuageFloat64(b *testing.B) {
- g := NewGaugeFloat64()
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- g.Update(float64(i))
- }
-}
-
-func TestGaugeFloat64(t *testing.T) {
- g := NewGaugeFloat64()
- g.Update(float64(47.0))
- if v := g.Value(); float64(47.0) != v {
- t.Errorf("g.Value(): 47.0 != %v\n", v)
- }
-}
-
-func TestGaugeFloat64Snapshot(t *testing.T) {
- g := NewGaugeFloat64()
- g.Update(float64(47.0))
- snapshot := g.Snapshot()
- g.Update(float64(0))
- if v := snapshot.Value(); float64(47.0) != v {
- t.Errorf("g.Value(): 47.0 != %v\n", v)
- }
-}
-
-func TestGetOrRegisterGaugeFloat64(t *testing.T) {
- r := NewRegistry()
- NewRegisteredGaugeFloat64("foo", r).Update(float64(47.0))
- t.Logf("registry: %v", r)
- if g := GetOrRegisterGaugeFloat64("foo", r); float64(47.0) != g.Value() {
- t.Fatal(g)
- }
-}
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/gauge_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/gauge_test.go
deleted file mode 100644
index 508496291..000000000
--- a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/gauge_test.go
+++ /dev/null
@@ -1,37 +0,0 @@
-package metrics
-
-import "testing"
-
-func BenchmarkGuage(b *testing.B) {
- g := NewGauge()
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- g.Update(int64(i))
- }
-}
-
-func TestGauge(t *testing.T) {
- g := NewGauge()
- g.Update(int64(47))
- if v := g.Value(); 47 != v {
- t.Errorf("g.Value(): 47 != %v\n", v)
- }
-}
-
-func TestGaugeSnapshot(t *testing.T) {
- g := NewGauge()
- g.Update(int64(47))
- snapshot := g.Snapshot()
- g.Update(int64(0))
- if v := snapshot.Value(); 47 != v {
- t.Errorf("g.Value(): 47 != %v\n", v)
- }
-}
-
-func TestGetOrRegisterGauge(t *testing.T) {
- r := NewRegistry()
- NewRegisteredGauge("foo", r).Update(47)
- if g := GetOrRegisterGauge("foo", r); 47 != g.Value() {
- t.Fatal(g)
- }
-}
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/graphite.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/graphite.go
index 604b26da0..abd0a7d29 100644
--- a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/graphite.go
+++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/graphite.go
@@ -38,6 +38,7 @@ func Graphite(r Registry, d time.Duration, prefix string, addr *net.TCPAddr) {
// GraphiteWithConfig is a blocking exporter function just like Graphite,
// but it takes a GraphiteConfig instead.
func GraphiteWithConfig(c GraphiteConfig) {
+ log.Printf("WARNING: This go-metrics client has been DEPRECATED! It has been moved to https://github.com/cyberdelia/go-metrics-graphite and will be removed from rcrowley/go-metrics on August 12th 2015")
for _ = range time.Tick(c.FlushInterval) {
if err := graphite(&c); nil != err {
log.Println(err)
@@ -49,6 +50,7 @@ func GraphiteWithConfig(c GraphiteConfig) {
// non-nil error on failed connections. This can be used in a loop
// similar to GraphiteWithConfig for custom error handling.
func GraphiteOnce(c GraphiteConfig) error {
+ log.Printf("WARNING: This go-metrics client has been DEPRECATED! It has been moved to https://github.com/cyberdelia/go-metrics-graphite and will be removed from rcrowley/go-metrics on August 12th 2015")
return graphite(&c)
}
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/graphite_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/graphite_test.go
deleted file mode 100644
index b49dc4bb5..000000000
--- a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/graphite_test.go
+++ /dev/null
@@ -1,22 +0,0 @@
-package metrics
-
-import (
- "net"
- "time"
-)
-
-func ExampleGraphite() {
- addr, _ := net.ResolveTCPAddr("net", ":2003")
- go Graphite(DefaultRegistry, 1*time.Second, "some.prefix", addr)
-}
-
-func ExampleGraphiteWithConfig() {
- addr, _ := net.ResolveTCPAddr("net", ":2003")
- go GraphiteWithConfig(GraphiteConfig{
- Addr: addr,
- Registry: DefaultRegistry,
- FlushInterval: 1 * time.Second,
- DurationUnit: time.Millisecond,
- Percentiles: []float64{ 0.5, 0.75, 0.99, 0.999 },
- })
-}
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/histogram_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/histogram_test.go
deleted file mode 100644
index d7f4f0171..000000000
--- a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/histogram_test.go
+++ /dev/null
@@ -1,95 +0,0 @@
-package metrics
-
-import "testing"
-
-func BenchmarkHistogram(b *testing.B) {
- h := NewHistogram(NewUniformSample(100))
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- h.Update(int64(i))
- }
-}
-
-func TestGetOrRegisterHistogram(t *testing.T) {
- r := NewRegistry()
- s := NewUniformSample(100)
- NewRegisteredHistogram("foo", r, s).Update(47)
- if h := GetOrRegisterHistogram("foo", r, s); 1 != h.Count() {
- t.Fatal(h)
- }
-}
-
-func TestHistogram10000(t *testing.T) {
- h := NewHistogram(NewUniformSample(100000))
- for i := 1; i <= 10000; i++ {
- h.Update(int64(i))
- }
- testHistogram10000(t, h)
-}
-
-func TestHistogramEmpty(t *testing.T) {
- h := NewHistogram(NewUniformSample(100))
- if count := h.Count(); 0 != count {
- t.Errorf("h.Count(): 0 != %v\n", count)
- }
- if min := h.Min(); 0 != min {
- t.Errorf("h.Min(): 0 != %v\n", min)
- }
- if max := h.Max(); 0 != max {
- t.Errorf("h.Max(): 0 != %v\n", max)
- }
- if mean := h.Mean(); 0.0 != mean {
- t.Errorf("h.Mean(): 0.0 != %v\n", mean)
- }
- if stdDev := h.StdDev(); 0.0 != stdDev {
- t.Errorf("h.StdDev(): 0.0 != %v\n", stdDev)
- }
- ps := h.Percentiles([]float64{0.5, 0.75, 0.99})
- if 0.0 != ps[0] {
- t.Errorf("median: 0.0 != %v\n", ps[0])
- }
- if 0.0 != ps[1] {
- t.Errorf("75th percentile: 0.0 != %v\n", ps[1])
- }
- if 0.0 != ps[2] {
- t.Errorf("99th percentile: 0.0 != %v\n", ps[2])
- }
-}
-
-func TestHistogramSnapshot(t *testing.T) {
- h := NewHistogram(NewUniformSample(100000))
- for i := 1; i <= 10000; i++ {
- h.Update(int64(i))
- }
- snapshot := h.Snapshot()
- h.Update(0)
- testHistogram10000(t, snapshot)
-}
-
-func testHistogram10000(t *testing.T, h Histogram) {
- if count := h.Count(); 10000 != count {
- t.Errorf("h.Count(): 10000 != %v\n", count)
- }
- if min := h.Min(); 1 != min {
- t.Errorf("h.Min(): 1 != %v\n", min)
- }
- if max := h.Max(); 10000 != max {
- t.Errorf("h.Max(): 10000 != %v\n", max)
- }
- if mean := h.Mean(); 5000.5 != mean {
- t.Errorf("h.Mean(): 5000.5 != %v\n", mean)
- }
- if stdDev := h.StdDev(); 2886.751331514372 != stdDev {
- t.Errorf("h.StdDev(): 2886.751331514372 != %v\n", stdDev)
- }
- ps := h.Percentiles([]float64{0.5, 0.75, 0.99})
- if 5000.5 != ps[0] {
- t.Errorf("median: 5000.5 != %v\n", ps[0])
- }
- if 7500.75 != ps[1] {
- t.Errorf("75th percentile: 7500.75 != %v\n", ps[1])
- }
- if 9900.99 != ps[2] {
- t.Errorf("99th percentile: 9900.99 != %v\n", ps[2])
- }
-}
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/influxdb/influxdb.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/influxdb/influxdb.go
deleted file mode 100644
index 0163c9b42..000000000
--- a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/influxdb/influxdb.go
+++ /dev/null
@@ -1,114 +0,0 @@
-package influxdb
-
-import (
- "fmt"
- influxClient "github.com/influxdb/influxdb/client"
- "github.com/rcrowley/go-metrics"
- "log"
- "time"
-)
-
-type Config struct {
- Host string
- Database string
- Username string
- Password string
-}
-
-func Influxdb(r metrics.Registry, d time.Duration, config *Config) {
- client, err := influxClient.NewClient(&influxClient.ClientConfig{
- Host: config.Host,
- Database: config.Database,
- Username: config.Username,
- Password: config.Password,
- })
- if err != nil {
- log.Println(err)
- return
- }
-
- for _ = range time.Tick(d) {
- if err := send(r, client); err != nil {
- log.Println(err)
- }
- }
-}
-
-func send(r metrics.Registry, client *influxClient.Client) error {
- series := []*influxClient.Series{}
-
- r.Each(func(name string, i interface{}) {
- now := getCurrentTime()
- switch metric := i.(type) {
- case metrics.Counter:
- series = append(series, &influxClient.Series{
- Name: fmt.Sprintf("%s.count", name),
- Columns: []string{"time", "count"},
- Points: [][]interface{}{
- {now, metric.Count()},
- },
- })
- case metrics.Gauge:
- series = append(series, &influxClient.Series{
- Name: fmt.Sprintf("%s.value", name),
- Columns: []string{"time", "value"},
- Points: [][]interface{}{
- {now, metric.Value()},
- },
- })
- case metrics.GaugeFloat64:
- series = append(series, &influxClient.Series{
- Name: fmt.Sprintf("%s.value", name),
- Columns: []string{"time", "value"},
- Points: [][]interface{}{
- {now, metric.Value()},
- },
- })
- case metrics.Histogram:
- h := metric.Snapshot()
- ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
- series = append(series, &influxClient.Series{
- Name: fmt.Sprintf("%s.histogram", name),
- Columns: []string{"time", "count", "min", "max", "mean", "std-dev",
- "50-percentile", "75-percentile", "95-percentile",
- "99-percentile", "999-percentile"},
- Points: [][]interface{}{
- {now, h.Count(), h.Min(), h.Max(), h.Mean(), h.StdDev(),
- ps[0], ps[1], ps[2], ps[3], ps[4]},
- },
- })
- case metrics.Meter:
- m := metric.Snapshot()
- series = append(series, &influxClient.Series{
- Name: fmt.Sprintf("%s.meter", name),
- Columns: []string{"count", "one-minute",
- "five-minute", "fifteen-minute", "mean"},
- Points: [][]interface{}{
- {m.Count(), m.Rate1(), m.Rate5(), m.Rate15(), m.RateMean()},
- },
- })
- case metrics.Timer:
- h := metric.Snapshot()
- ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
- series = append(series, &influxClient.Series{
- Name: fmt.Sprintf("%s.timer", name),
- Columns: []string{"count", "min", "max", "mean", "std-dev",
- "50-percentile", "75-percentile", "95-percentile",
- "99-percentile", "999-percentile", "one-minute", "five-minute", "fifteen-minute", "mean-rate"},
- Points: [][]interface{}{
- {h.Count(), h.Min(), h.Max(), h.Mean(), h.StdDev(),
- ps[0], ps[1], ps[2], ps[3], ps[4],
- h.Rate1(), h.Rate5(), h.Rate15(), h.RateMean()},
- },
- })
- }
- })
- if err := client.WriteSeries(series); err != nil {
- log.Println(err)
- }
- return nil
-}
-
-func getCurrentTime() int64 {
- return time.Now().UnixNano() / 1000000
-}
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/json.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/json.go
index 04a9c9198..2676aeea5 100644
--- a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/json.go
+++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/json.go
@@ -8,7 +8,7 @@ import (
// MarshalJSON returns a byte slice containing a JSON representation of all
// the metrics in the Registry.
-func (r StandardRegistry) MarshalJSON() ([]byte, error) {
+func (r *StandardRegistry) MarshalJSON() ([]byte, error) {
data := make(map[string]map[string]interface{})
r.Each(func(name string, i interface{}) {
values := make(map[string]interface{})
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/json_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/json_test.go
deleted file mode 100644
index cf70051f7..000000000
--- a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/json_test.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package metrics
-
-import (
- "bytes"
- "encoding/json"
- "testing"
-)
-
-func TestRegistryMarshallJSON(t *testing.T) {
- b := &bytes.Buffer{}
- enc := json.NewEncoder(b)
- r := NewRegistry()
- r.Register("counter", NewCounter())
- enc.Encode(r)
- if s := b.String(); "{\"counter\":{\"count\":0}}\n" != s {
- t.Fatalf(s)
- }
-}
-
-func TestRegistryWriteJSONOnce(t *testing.T) {
- r := NewRegistry()
- r.Register("counter", NewCounter())
- b := &bytes.Buffer{}
- WriteJSONOnce(r, b)
- if s := b.String(); s != "{\"counter\":{\"count\":0}}\n" {
- t.Fail()
- }
-}
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/librato/librato.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/librato/librato.go
index dfaae2f28..d7c057468 100644
--- a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/librato/librato.go
+++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/librato/librato.go
@@ -23,6 +23,7 @@ func translateTimerAttributes(d time.Duration) (attrs map[string]interface{}) {
type Reporter struct {
Email, Token string
+ Namespace string
Source string
Interval time.Duration
Registry metrics.Registry
@@ -32,7 +33,7 @@ type Reporter struct {
}
func NewReporter(r metrics.Registry, d time.Duration, e string, t string, s string, p []float64, u time.Duration) *Reporter {
- return &Reporter{e, t, s, d, r, p, translateTimerAttributes(u), int64(d / time.Second)}
+ return &Reporter{e, t, "", s, d, r, p, translateTimerAttributes(u), int64(d / time.Second)}
}
func Librato(r metrics.Registry, d time.Duration, e string, t string, s string, p []float64, u time.Duration) {
@@ -40,6 +41,7 @@ func Librato(r metrics.Registry, d time.Duration, e string, t string, s string,
}
func (self *Reporter) Run() {
+ log.Printf("WARNING: This client has been DEPRECATED! It has been moved to https://github.com/mihasya/go-metrics-librato and will be removed from rcrowley/go-metrics on August 5th 2015")
ticker := time.Tick(self.Interval)
metricsApi := &LibratoClient{self.Email, self.Token}
for now := range ticker {
@@ -87,6 +89,9 @@ func (self *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot
snapshot.Counters = make([]Measurement, 0)
histogramGaugeCount := 1 + len(self.Percentiles)
r.Each(func(name string, metric interface{}) {
+ if self.Namespace != "" {
+ name = fmt.Sprintf("%s.%s", self.Namespace, name)
+ }
measurement := Measurement{}
measurement[Period] = self.Interval.Seconds()
switch m := metric.(type) {
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/log.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/log.go
index 278a8a441..f074eb03d 100644
--- a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/log.go
+++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/log.go
@@ -5,10 +5,17 @@ import (
"time"
)
+func Log(r Registry, freq time.Duration, l *log.Logger) {
+ LogScaled(r, freq, time.Nanosecond, l)
+}
+
// Output each metric in the given registry periodically using the given
-// logger.
-func Log(r Registry, d time.Duration, l *log.Logger) {
- for _ = range time.Tick(d) {
+// logger. Print timings in `scale` units (eg time.Millisecond) rather than nanos.
+func LogScaled(r Registry, freq time.Duration, scale time.Duration, l *log.Logger) {
+ du := float64(scale)
+ duSuffix := scale.String()[1:]
+
+ for _ = range time.Tick(freq) {
r.Each(func(name string, i interface{}) {
switch metric := i.(type) {
case Counter:
@@ -51,15 +58,15 @@ func Log(r Registry, d time.Duration, l *log.Logger) {
ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
l.Printf("timer %s\n", name)
l.Printf(" count: %9d\n", t.Count())
- l.Printf(" min: %9d\n", t.Min())
- l.Printf(" max: %9d\n", t.Max())
- l.Printf(" mean: %12.2f\n", t.Mean())
- l.Printf(" stddev: %12.2f\n", t.StdDev())
- l.Printf(" median: %12.2f\n", ps[0])
- l.Printf(" 75%%: %12.2f\n", ps[1])
- l.Printf(" 95%%: %12.2f\n", ps[2])
- l.Printf(" 99%%: %12.2f\n", ps[3])
- l.Printf(" 99.9%%: %12.2f\n", ps[4])
+ l.Printf(" min: %12.2f%s\n", float64(t.Min())/du, duSuffix)
+ l.Printf(" max: %12.2f%s\n", float64(t.Max())/du, duSuffix)
+ l.Printf(" mean: %12.2f%s\n", t.Mean()/du, duSuffix)
+ l.Printf(" stddev: %12.2f%s\n", t.StdDev()/du, duSuffix)
+ l.Printf(" median: %12.2f%s\n", ps[0]/du, duSuffix)
+ l.Printf(" 75%%: %12.2f%s\n", ps[1]/du, duSuffix)
+ l.Printf(" 95%%: %12.2f%s\n", ps[2]/du, duSuffix)
+ l.Printf(" 99%%: %12.2f%s\n", ps[3]/du, duSuffix)
+ l.Printf(" 99.9%%: %12.2f%s\n", ps[4]/du, duSuffix)
l.Printf(" 1-min rate: %12.2f\n", t.Rate1())
l.Printf(" 5-min rate: %12.2f\n", t.Rate5())
l.Printf(" 15-min rate: %12.2f\n", t.Rate15())
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/meter_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/meter_test.go
deleted file mode 100644
index 26ce1398a..000000000
--- a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/meter_test.go
+++ /dev/null
@@ -1,60 +0,0 @@
-package metrics
-
-import (
- "testing"
- "time"
-)
-
-func BenchmarkMeter(b *testing.B) {
- m := NewMeter()
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- m.Mark(1)
- }
-}
-
-func TestGetOrRegisterMeter(t *testing.T) {
- r := NewRegistry()
- NewRegisteredMeter("foo", r).Mark(47)
- if m := GetOrRegisterMeter("foo", r); 47 != m.Count() {
- t.Fatal(m)
- }
-}
-
-func TestMeterDecay(t *testing.T) {
- ma := meterArbiter{
- ticker: time.NewTicker(1),
- }
- m := newStandardMeter()
- ma.meters = append(ma.meters, m)
- go ma.tick()
- m.Mark(1)
- rateMean := m.RateMean()
- time.Sleep(1)
- if m.RateMean() >= rateMean {
- t.Error("m.RateMean() didn't decrease")
- }
-}
-
-func TestMeterNonzero(t *testing.T) {
- m := NewMeter()
- m.Mark(3)
- if count := m.Count(); 3 != count {
- t.Errorf("m.Count(): 3 != %v\n", count)
- }
-}
-
-func TestMeterSnapshot(t *testing.T) {
- m := NewMeter()
- m.Mark(1)
- if snapshot := m.Snapshot(); m.RateMean() != snapshot.RateMean() {
- t.Fatal(snapshot)
- }
-}
-
-func TestMeterZero(t *testing.T) {
- m := NewMeter()
- if count := m.Count(); 0 != count {
- t.Errorf("m.Count(): 0 != %v\n", count)
- }
-}
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/metrics_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/metrics_test.go
deleted file mode 100644
index 083f9676f..000000000
--- a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/metrics_test.go
+++ /dev/null
@@ -1,107 +0,0 @@
-package metrics
-
-import (
- "io/ioutil"
- "log"
- "sync"
- "testing"
-)
-
-const FANOUT = 128
-
-// Stop the compiler from complaining during debugging.
-var (
- _ = ioutil.Discard
- _ = log.LstdFlags
-)
-
-func BenchmarkMetrics(b *testing.B) {
- r := NewRegistry()
- c := NewRegisteredCounter("counter", r)
- g := NewRegisteredGauge("gauge", r)
- gf := NewRegisteredGaugeFloat64("gaugefloat64", r)
- h := NewRegisteredHistogram("histogram", r, NewUniformSample(100))
- m := NewRegisteredMeter("meter", r)
- t := NewRegisteredTimer("timer", r)
- RegisterDebugGCStats(r)
- RegisterRuntimeMemStats(r)
- b.ResetTimer()
- ch := make(chan bool)
-
- wgD := &sync.WaitGroup{}
- /*
- wgD.Add(1)
- go func() {
- defer wgD.Done()
- //log.Println("go CaptureDebugGCStats")
- for {
- select {
- case <-ch:
- //log.Println("done CaptureDebugGCStats")
- return
- default:
- CaptureDebugGCStatsOnce(r)
- }
- }
- }()
- //*/
-
- wgR := &sync.WaitGroup{}
- //*
- wgR.Add(1)
- go func() {
- defer wgR.Done()
- //log.Println("go CaptureRuntimeMemStats")
- for {
- select {
- case <-ch:
- //log.Println("done CaptureRuntimeMemStats")
- return
- default:
- CaptureRuntimeMemStatsOnce(r)
- }
- }
- }()
- //*/
-
- wgW := &sync.WaitGroup{}
- /*
- wgW.Add(1)
- go func() {
- defer wgW.Done()
- //log.Println("go Write")
- for {
- select {
- case <-ch:
- //log.Println("done Write")
- return
- default:
- WriteOnce(r, ioutil.Discard)
- }
- }
- }()
- //*/
-
- wg := &sync.WaitGroup{}
- wg.Add(FANOUT)
- for i := 0; i < FANOUT; i++ {
- go func(i int) {
- defer wg.Done()
- //log.Println("go", i)
- for i := 0; i < b.N; i++ {
- c.Inc(1)
- g.Update(int64(i))
- gf.Update(float64(i))
- h.Update(int64(i))
- m.Mark(1)
- t.Update(1)
- }
- //log.Println("done", i)
- }(i)
- }
- wg.Wait()
- close(ch)
- wgD.Wait()
- wgR.Wait()
- wgW.Wait()
-}
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/opentsdb_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/opentsdb_test.go
deleted file mode 100644
index 6173d61ab..000000000
--- a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/opentsdb_test.go
+++ /dev/null
@@ -1,22 +0,0 @@
-package metrics
-
-import (
- "net"
- "time"
-)
-
-func ExampleOpenTSDB() {
- addr, _ := net.ResolveTCPAddr("net", ":2003")
- go OpenTSDB(DefaultRegistry, 1*time.Second, "some.prefix", addr)
-}
-
-func ExampleOpenTSDBWithConfig() {
- addr, _ := net.ResolveTCPAddr("net", ":2003")
- go OpenTSDBWithConfig(OpenTSDBConfig{
- Addr: addr,
- Registry: DefaultRegistry,
- FlushInterval: 1 * time.Second,
- DurationUnit: time.Millisecond,
- })
-}
-
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/registry.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/registry.go
index 1f9d82c2a..e1f68a5dc 100644
--- a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/registry.go
+++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/registry.go
@@ -145,6 +145,65 @@ func (r *StandardRegistry) registered() map[string]interface{} {
return metrics
}
+type PrefixedRegistry struct {
+ underlying Registry
+ prefix string
+}
+
+func NewPrefixedRegistry(prefix string) Registry {
+ return &PrefixedRegistry{
+ underlying: NewRegistry(),
+ prefix: prefix,
+ }
+}
+
+func NewPrefixedChildRegistry(parent Registry, prefix string) Registry {
+ return &PrefixedRegistry{
+ underlying: parent,
+ prefix: prefix,
+ }
+}
+
+// Call the given function for each registered metric.
+func (r *PrefixedRegistry) Each(fn func(string, interface{})) {
+ r.underlying.Each(fn)
+}
+
+// Get the metric by the given name or nil if none is registered.
+func (r *PrefixedRegistry) Get(name string) interface{} {
+ return r.underlying.Get(name)
+}
+
+// Gets an existing metric or registers the given one.
+// The interface can be the metric to register if not found in registry,
+// or a function returning the metric for lazy instantiation.
+func (r *PrefixedRegistry) GetOrRegister(name string, metric interface{}) interface{} {
+ realName := r.prefix + name
+ return r.underlying.GetOrRegister(realName, metric)
+}
+
+// Register the given metric under the given name. The name will be prefixed.
+func (r *PrefixedRegistry) Register(name string, metric interface{}) error {
+ realName := r.prefix + name
+ return r.underlying.Register(realName, metric)
+}
+
+// Run all registered healthchecks.
+func (r *PrefixedRegistry) RunHealthchecks() {
+ r.underlying.RunHealthchecks()
+}
+
+// Unregister the metric with the given name. The name will be prefixed.
+func (r *PrefixedRegistry) Unregister(name string) {
+ realName := r.prefix + name
+ r.underlying.Unregister(realName)
+}
+
+// Unregister all metrics. (Mostly for testing.)
+func (r *PrefixedRegistry) UnregisterAll() {
+ r.underlying.UnregisterAll()
+}
+
var DefaultRegistry Registry = NewRegistry()
// Call the given function for each registered metric.
@@ -169,6 +228,14 @@ func Register(name string, i interface{}) error {
return DefaultRegistry.Register(name, i)
}
+// Register the given metric under the given name. Panics if a metric by the
+// given name is already registered.
+func MustRegister(name string, i interface{}) {
+ if err := Register(name, i); err != nil {
+ panic(err)
+ }
+}
+
// Run all registered healthchecks.
func RunHealthchecks() {
DefaultRegistry.RunHealthchecks()
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/registry_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/registry_test.go
deleted file mode 100644
index 9ba0a0205..000000000
--- a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/registry_test.go
+++ /dev/null
@@ -1,118 +0,0 @@
-package metrics
-
-import "testing"
-
-func BenchmarkRegistry(b *testing.B) {
- r := NewRegistry()
- r.Register("foo", NewCounter())
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- r.Each(func(string, interface{}) {})
- }
-}
-
-func TestRegistry(t *testing.T) {
- r := NewRegistry()
- r.Register("foo", NewCounter())
- i := 0
- r.Each(func(name string, iface interface{}) {
- i++
- if "foo" != name {
- t.Fatal(name)
- }
- if _, ok := iface.(Counter); !ok {
- t.Fatal(iface)
- }
- })
- if 1 != i {
- t.Fatal(i)
- }
- r.Unregister("foo")
- i = 0
- r.Each(func(string, interface{}) { i++ })
- if 0 != i {
- t.Fatal(i)
- }
-}
-
-func TestRegistryDuplicate(t *testing.T) {
- r := NewRegistry()
- if err := r.Register("foo", NewCounter()); nil != err {
- t.Fatal(err)
- }
- if err := r.Register("foo", NewGauge()); nil == err {
- t.Fatal(err)
- }
- i := 0
- r.Each(func(name string, iface interface{}) {
- i++
- if _, ok := iface.(Counter); !ok {
- t.Fatal(iface)
- }
- })
- if 1 != i {
- t.Fatal(i)
- }
-}
-
-func TestRegistryGet(t *testing.T) {
- r := NewRegistry()
- r.Register("foo", NewCounter())
- if count := r.Get("foo").(Counter).Count(); 0 != count {
- t.Fatal(count)
- }
- r.Get("foo").(Counter).Inc(1)
- if count := r.Get("foo").(Counter).Count(); 1 != count {
- t.Fatal(count)
- }
-}
-
-func TestRegistryGetOrRegister(t *testing.T) {
- r := NewRegistry()
-
- // First metric wins with GetOrRegister
- _ = r.GetOrRegister("foo", NewCounter())
- m := r.GetOrRegister("foo", NewGauge())
- if _, ok := m.(Counter); !ok {
- t.Fatal(m)
- }
-
- i := 0
- r.Each(func(name string, iface interface{}) {
- i++
- if name != "foo" {
- t.Fatal(name)
- }
- if _, ok := iface.(Counter); !ok {
- t.Fatal(iface)
- }
- })
- if i != 1 {
- t.Fatal(i)
- }
-}
-
-func TestRegistryGetOrRegisterWithLazyInstantiation(t *testing.T) {
- r := NewRegistry()
-
- // First metric wins with GetOrRegister
- _ = r.GetOrRegister("foo", NewCounter)
- m := r.GetOrRegister("foo", NewGauge)
- if _, ok := m.(Counter); !ok {
- t.Fatal(m)
- }
-
- i := 0
- r.Each(func(name string, iface interface{}) {
- i++
- if name != "foo" {
- t.Fatal(name)
- }
- if _, ok := iface.(Counter); !ok {
- t.Fatal(iface)
- }
- })
- if i != 1 {
- t.Fatal(i)
- }
-}
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime.go
index 82574bf25..e8c8d1568 100644
--- a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime.go
+++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime.go
@@ -9,32 +9,33 @@ var (
memStats runtime.MemStats
runtimeMetrics struct {
MemStats struct {
- Alloc Gauge
- BuckHashSys Gauge
- DebugGC Gauge
- EnableGC Gauge
- Frees Gauge
- HeapAlloc Gauge
- HeapIdle Gauge
- HeapInuse Gauge
- HeapObjects Gauge
- HeapReleased Gauge
- HeapSys Gauge
- LastGC Gauge
- Lookups Gauge
- Mallocs Gauge
- MCacheInuse Gauge
- MCacheSys Gauge
- MSpanInuse Gauge
- MSpanSys Gauge
- NextGC Gauge
- NumGC Gauge
- PauseNs Histogram
- PauseTotalNs Gauge
- StackInuse Gauge
- StackSys Gauge
- Sys Gauge
- TotalAlloc Gauge
+ Alloc Gauge
+ BuckHashSys Gauge
+ DebugGC Gauge
+ EnableGC Gauge
+ Frees Gauge
+ HeapAlloc Gauge
+ HeapIdle Gauge
+ HeapInuse Gauge
+ HeapObjects Gauge
+ HeapReleased Gauge
+ HeapSys Gauge
+ LastGC Gauge
+ Lookups Gauge
+ Mallocs Gauge
+ MCacheInuse Gauge
+ MCacheSys Gauge
+ MSpanInuse Gauge
+ MSpanSys Gauge
+ NextGC Gauge
+ NumGC Gauge
+ GCCPUFraction GaugeFloat64
+ PauseNs Histogram
+ PauseTotalNs Gauge
+ StackInuse Gauge
+ StackSys Gauge
+ Sys Gauge
+ TotalAlloc Gauge
}
NumCgoCall Gauge
NumGoroutine Gauge
@@ -97,6 +98,7 @@ func CaptureRuntimeMemStatsOnce(r Registry) {
runtimeMetrics.MemStats.MSpanSys.Update(int64(memStats.MSpanSys))
runtimeMetrics.MemStats.NextGC.Update(int64(memStats.NextGC))
runtimeMetrics.MemStats.NumGC.Update(int64(memStats.NumGC - numGC))
+ runtimeMetrics.MemStats.GCCPUFraction.Update(gcCPUFraction(&memStats))
// <https://code.google.com/p/go/source/browse/src/pkg/runtime/mgc0.c>
i := numGC % uint32(len(memStats.PauseNs))
@@ -158,6 +160,7 @@ func RegisterRuntimeMemStats(r Registry) {
runtimeMetrics.MemStats.MSpanSys = NewGauge()
runtimeMetrics.MemStats.NextGC = NewGauge()
runtimeMetrics.MemStats.NumGC = NewGauge()
+ runtimeMetrics.MemStats.GCCPUFraction = NewGaugeFloat64()
runtimeMetrics.MemStats.PauseNs = NewHistogram(NewExpDecaySample(1028, 0.015))
runtimeMetrics.MemStats.PauseTotalNs = NewGauge()
runtimeMetrics.MemStats.StackInuse = NewGauge()
@@ -188,6 +191,7 @@ func RegisterRuntimeMemStats(r Registry) {
r.Register("runtime.MemStats.MSpanSys", runtimeMetrics.MemStats.MSpanSys)
r.Register("runtime.MemStats.NextGC", runtimeMetrics.MemStats.NextGC)
r.Register("runtime.MemStats.NumGC", runtimeMetrics.MemStats.NumGC)
+ r.Register("runtime.MemStats.GCCPUFraction", runtimeMetrics.MemStats.GCCPUFraction)
r.Register("runtime.MemStats.PauseNs", runtimeMetrics.MemStats.PauseNs)
r.Register("runtime.MemStats.PauseTotalNs", runtimeMetrics.MemStats.PauseTotalNs)
r.Register("runtime.MemStats.StackInuse", runtimeMetrics.MemStats.StackInuse)
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime_gccpufraction.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime_gccpufraction.go
new file mode 100644
index 000000000..ca12c05ba
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime_gccpufraction.go
@@ -0,0 +1,9 @@
+// +build go1.5
+
+package metrics
+
+import "runtime"
+
+func gcCPUFraction(memStats *runtime.MemStats) float64 {
+ return memStats.GCCPUFraction
+}
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime_no_gccpufraction.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime_no_gccpufraction.go
new file mode 100644
index 000000000..be96aa6f1
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime_no_gccpufraction.go
@@ -0,0 +1,9 @@
+// +build !go1.5
+
+package metrics
+
+import "runtime"
+
+func gcCPUFraction(memStats *runtime.MemStats) float64 {
+ return 0
+}
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime_test.go
deleted file mode 100644
index a0ca89479..000000000
--- a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/runtime_test.go
+++ /dev/null
@@ -1,78 +0,0 @@
-package metrics
-
-import (
- "runtime"
- "testing"
- "time"
-)
-
-func BenchmarkRuntimeMemStats(b *testing.B) {
- r := NewRegistry()
- RegisterRuntimeMemStats(r)
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- CaptureRuntimeMemStatsOnce(r)
- }
-}
-
-func TestRuntimeMemStats(t *testing.T) {
- r := NewRegistry()
- RegisterRuntimeMemStats(r)
- CaptureRuntimeMemStatsOnce(r)
- zero := runtimeMetrics.MemStats.PauseNs.Count() // Get a "zero" since GC may have run before these tests.
- runtime.GC()
- CaptureRuntimeMemStatsOnce(r)
- if count := runtimeMetrics.MemStats.PauseNs.Count(); 1 != count-zero {
- t.Fatal(count - zero)
- }
- runtime.GC()
- runtime.GC()
- CaptureRuntimeMemStatsOnce(r)
- if count := runtimeMetrics.MemStats.PauseNs.Count(); 3 != count-zero {
- t.Fatal(count - zero)
- }
- for i := 0; i < 256; i++ {
- runtime.GC()
- }
- CaptureRuntimeMemStatsOnce(r)
- if count := runtimeMetrics.MemStats.PauseNs.Count(); 259 != count-zero {
- t.Fatal(count - zero)
- }
- for i := 0; i < 257; i++ {
- runtime.GC()
- }
- CaptureRuntimeMemStatsOnce(r)
- if count := runtimeMetrics.MemStats.PauseNs.Count(); 515 != count-zero { // We lost one because there were too many GCs between captures.
- t.Fatal(count - zero)
- }
-}
-
-func TestRuntimeMemStatsBlocking(t *testing.T) {
- if g := runtime.GOMAXPROCS(0); g < 2 {
- t.Skipf("skipping TestRuntimeMemStatsBlocking with GOMAXPROCS=%d\n", g)
- }
- ch := make(chan int)
- go testRuntimeMemStatsBlocking(ch)
- var memStats runtime.MemStats
- t0 := time.Now()
- runtime.ReadMemStats(&memStats)
- t1 := time.Now()
- t.Log("i++ during runtime.ReadMemStats:", <-ch)
- go testRuntimeMemStatsBlocking(ch)
- d := t1.Sub(t0)
- t.Log(d)
- time.Sleep(d)
- t.Log("i++ during time.Sleep:", <-ch)
-}
-
-func testRuntimeMemStatsBlocking(ch chan int) {
- i := 0
- for {
- select {
- case ch <- i:
- return
- default:
- i++
- }
- }
-}
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/sample_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/sample_test.go
deleted file mode 100644
index d60e99c5b..000000000
--- a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/sample_test.go
+++ /dev/null
@@ -1,363 +0,0 @@
-package metrics
-
-import (
- "math/rand"
- "runtime"
- "testing"
- "time"
-)
-
-// Benchmark{Compute,Copy}{1000,1000000} demonstrate that, even for relatively
-// expensive computations like Variance, the cost of copying the Sample, as
-// approximated by a make and copy, is much greater than the cost of the
-// computation for small samples and only slightly less for large samples.
-func BenchmarkCompute1000(b *testing.B) {
- s := make([]int64, 1000)
- for i := 0; i < len(s); i++ {
- s[i] = int64(i)
- }
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- SampleVariance(s)
- }
-}
-func BenchmarkCompute1000000(b *testing.B) {
- s := make([]int64, 1000000)
- for i := 0; i < len(s); i++ {
- s[i] = int64(i)
- }
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- SampleVariance(s)
- }
-}
-func BenchmarkCopy1000(b *testing.B) {
- s := make([]int64, 1000)
- for i := 0; i < len(s); i++ {
- s[i] = int64(i)
- }
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- sCopy := make([]int64, len(s))
- copy(sCopy, s)
- }
-}
-func BenchmarkCopy1000000(b *testing.B) {
- s := make([]int64, 1000000)
- for i := 0; i < len(s); i++ {
- s[i] = int64(i)
- }
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- sCopy := make([]int64, len(s))
- copy(sCopy, s)
- }
-}
-
-func BenchmarkExpDecaySample257(b *testing.B) {
- benchmarkSample(b, NewExpDecaySample(257, 0.015))
-}
-
-func BenchmarkExpDecaySample514(b *testing.B) {
- benchmarkSample(b, NewExpDecaySample(514, 0.015))
-}
-
-func BenchmarkExpDecaySample1028(b *testing.B) {
- benchmarkSample(b, NewExpDecaySample(1028, 0.015))
-}
-
-func BenchmarkUniformSample257(b *testing.B) {
- benchmarkSample(b, NewUniformSample(257))
-}
-
-func BenchmarkUniformSample514(b *testing.B) {
- benchmarkSample(b, NewUniformSample(514))
-}
-
-func BenchmarkUniformSample1028(b *testing.B) {
- benchmarkSample(b, NewUniformSample(1028))
-}
-
-func TestExpDecaySample10(t *testing.T) {
- rand.Seed(1)
- s := NewExpDecaySample(100, 0.99)
- for i := 0; i < 10; i++ {
- s.Update(int64(i))
- }
- if size := s.Count(); 10 != size {
- t.Errorf("s.Count(): 10 != %v\n", size)
- }
- if size := s.Size(); 10 != size {
- t.Errorf("s.Size(): 10 != %v\n", size)
- }
- if l := len(s.Values()); 10 != l {
- t.Errorf("len(s.Values()): 10 != %v\n", l)
- }
- for _, v := range s.Values() {
- if v > 10 || v < 0 {
- t.Errorf("out of range [0, 10): %v\n", v)
- }
- }
-}
-
-func TestExpDecaySample100(t *testing.T) {
- rand.Seed(1)
- s := NewExpDecaySample(1000, 0.01)
- for i := 0; i < 100; i++ {
- s.Update(int64(i))
- }
- if size := s.Count(); 100 != size {
- t.Errorf("s.Count(): 100 != %v\n", size)
- }
- if size := s.Size(); 100 != size {
- t.Errorf("s.Size(): 100 != %v\n", size)
- }
- if l := len(s.Values()); 100 != l {
- t.Errorf("len(s.Values()): 100 != %v\n", l)
- }
- for _, v := range s.Values() {
- if v > 100 || v < 0 {
- t.Errorf("out of range [0, 100): %v\n", v)
- }
- }
-}
-
-func TestExpDecaySample1000(t *testing.T) {
- rand.Seed(1)
- s := NewExpDecaySample(100, 0.99)
- for i := 0; i < 1000; i++ {
- s.Update(int64(i))
- }
- if size := s.Count(); 1000 != size {
- t.Errorf("s.Count(): 1000 != %v\n", size)
- }
- if size := s.Size(); 100 != size {
- t.Errorf("s.Size(): 100 != %v\n", size)
- }
- if l := len(s.Values()); 100 != l {
- t.Errorf("len(s.Values()): 100 != %v\n", l)
- }
- for _, v := range s.Values() {
- if v > 1000 || v < 0 {
- t.Errorf("out of range [0, 1000): %v\n", v)
- }
- }
-}
-
-// This test makes sure that the sample's priority is not amplified by using
-// nanosecond duration since start rather than second duration since start.
-// The priority becomes +Inf quickly after starting if this is done,
-// effectively freezing the set of samples until a rescale step happens.
-func TestExpDecaySampleNanosecondRegression(t *testing.T) {
- rand.Seed(1)
- s := NewExpDecaySample(100, 0.99)
- for i := 0; i < 100; i++ {
- s.Update(10)
- }
- time.Sleep(1 * time.Millisecond)
- for i := 0; i < 100; i++ {
- s.Update(20)
- }
- v := s.Values()
- avg := float64(0)
- for i := 0; i < len(v); i++ {
- avg += float64(v[i])
- }
- avg /= float64(len(v))
- if avg > 16 || avg < 14 {
- t.Errorf("out of range [14, 16]: %v\n", avg)
- }
-}
-
-func TestExpDecaySampleRescale(t *testing.T) {
- s := NewExpDecaySample(2, 0.001).(*ExpDecaySample)
- s.update(time.Now(), 1)
- s.update(time.Now().Add(time.Hour+time.Microsecond), 1)
- for _, v := range s.values.Values() {
- if v.k == 0.0 {
- t.Fatal("v.k == 0.0")
- }
- }
-}
-
-func TestExpDecaySampleSnapshot(t *testing.T) {
- now := time.Now()
- rand.Seed(1)
- s := NewExpDecaySample(100, 0.99)
- for i := 1; i <= 10000; i++ {
- s.(*ExpDecaySample).update(now.Add(time.Duration(i)), int64(i))
- }
- snapshot := s.Snapshot()
- s.Update(1)
- testExpDecaySampleStatistics(t, snapshot)
-}
-
-func TestExpDecaySampleStatistics(t *testing.T) {
- now := time.Now()
- rand.Seed(1)
- s := NewExpDecaySample(100, 0.99)
- for i := 1; i <= 10000; i++ {
- s.(*ExpDecaySample).update(now.Add(time.Duration(i)), int64(i))
- }
- testExpDecaySampleStatistics(t, s)
-}
-
-func TestUniformSample(t *testing.T) {
- rand.Seed(1)
- s := NewUniformSample(100)
- for i := 0; i < 1000; i++ {
- s.Update(int64(i))
- }
- if size := s.Count(); 1000 != size {
- t.Errorf("s.Count(): 1000 != %v\n", size)
- }
- if size := s.Size(); 100 != size {
- t.Errorf("s.Size(): 100 != %v\n", size)
- }
- if l := len(s.Values()); 100 != l {
- t.Errorf("len(s.Values()): 100 != %v\n", l)
- }
- for _, v := range s.Values() {
- if v > 1000 || v < 0 {
- t.Errorf("out of range [0, 100): %v\n", v)
- }
- }
-}
-
-func TestUniformSampleIncludesTail(t *testing.T) {
- rand.Seed(1)
- s := NewUniformSample(100)
- max := 100
- for i := 0; i < max; i++ {
- s.Update(int64(i))
- }
- v := s.Values()
- sum := 0
- exp := (max - 1) * max / 2
- for i := 0; i < len(v); i++ {
- sum += int(v[i])
- }
- if exp != sum {
- t.Errorf("sum: %v != %v\n", exp, sum)
- }
-}
-
-func TestUniformSampleSnapshot(t *testing.T) {
- s := NewUniformSample(100)
- for i := 1; i <= 10000; i++ {
- s.Update(int64(i))
- }
- snapshot := s.Snapshot()
- s.Update(1)
- testUniformSampleStatistics(t, snapshot)
-}
-
-func TestUniformSampleStatistics(t *testing.T) {
- rand.Seed(1)
- s := NewUniformSample(100)
- for i := 1; i <= 10000; i++ {
- s.Update(int64(i))
- }
- testUniformSampleStatistics(t, s)
-}
-
-func benchmarkSample(b *testing.B, s Sample) {
- var memStats runtime.MemStats
- runtime.ReadMemStats(&memStats)
- pauseTotalNs := memStats.PauseTotalNs
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- s.Update(1)
- }
- b.StopTimer()
- runtime.GC()
- runtime.ReadMemStats(&memStats)
- b.Logf("GC cost: %d ns/op", int(memStats.PauseTotalNs-pauseTotalNs)/b.N)
-}
-
-func testExpDecaySampleStatistics(t *testing.T, s Sample) {
- if count := s.Count(); 10000 != count {
- t.Errorf("s.Count(): 10000 != %v\n", count)
- }
- if min := s.Min(); 107 != min {
- t.Errorf("s.Min(): 107 != %v\n", min)
- }
- if max := s.Max(); 10000 != max {
- t.Errorf("s.Max(): 10000 != %v\n", max)
- }
- if mean := s.Mean(); 4965.98 != mean {
- t.Errorf("s.Mean(): 4965.98 != %v\n", mean)
- }
- if stdDev := s.StdDev(); 2959.825156930727 != stdDev {
- t.Errorf("s.StdDev(): 2959.825156930727 != %v\n", stdDev)
- }
- ps := s.Percentiles([]float64{0.5, 0.75, 0.99})
- if 4615 != ps[0] {
- t.Errorf("median: 4615 != %v\n", ps[0])
- }
- if 7672 != ps[1] {
- t.Errorf("75th percentile: 7672 != %v\n", ps[1])
- }
- if 9998.99 != ps[2] {
- t.Errorf("99th percentile: 9998.99 != %v\n", ps[2])
- }
-}
-
-func testUniformSampleStatistics(t *testing.T, s Sample) {
- if count := s.Count(); 10000 != count {
- t.Errorf("s.Count(): 10000 != %v\n", count)
- }
- if min := s.Min(); 37 != min {
- t.Errorf("s.Min(): 37 != %v\n", min)
- }
- if max := s.Max(); 9989 != max {
- t.Errorf("s.Max(): 9989 != %v\n", max)
- }
- if mean := s.Mean(); 4748.14 != mean {
- t.Errorf("s.Mean(): 4748.14 != %v\n", mean)
- }
- if stdDev := s.StdDev(); 2826.684117548333 != stdDev {
- t.Errorf("s.StdDev(): 2826.684117548333 != %v\n", stdDev)
- }
- ps := s.Percentiles([]float64{0.5, 0.75, 0.99})
- if 4599 != ps[0] {
- t.Errorf("median: 4599 != %v\n", ps[0])
- }
- if 7380.5 != ps[1] {
- t.Errorf("75th percentile: 7380.5 != %v\n", ps[1])
- }
- if 9986.429999999998 != ps[2] {
- t.Errorf("99th percentile: 9986.429999999998 != %v\n", ps[2])
- }
-}
-
-// TestUniformSampleConcurrentUpdateCount would expose data race problems with
-// concurrent Update and Count calls on Sample when test is called with -race
-// argument
-func TestUniformSampleConcurrentUpdateCount(t *testing.T) {
- if testing.Short() {
- t.Skip("skipping in short mode")
- }
- s := NewUniformSample(100)
- for i := 0; i < 100; i++ {
- s.Update(int64(i))
- }
- quit := make(chan struct{})
- go func() {
- t := time.NewTicker(10 * time.Millisecond)
- for {
- select {
- case <-t.C:
- s.Update(rand.Int63())
- case <-quit:
- t.Stop()
- return
- }
- }
- }()
- for i := 0; i < 1000; i++ {
- s.Count()
- time.Sleep(5 * time.Millisecond)
- }
- quit <- struct{}{}
-}
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/timer_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/timer_test.go
deleted file mode 100644
index 2fa415d40..000000000
--- a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/timer_test.go
+++ /dev/null
@@ -1,81 +0,0 @@
-package metrics
-
-import (
- "math"
- "testing"
- "time"
-)
-
-func BenchmarkTimer(b *testing.B) {
- tm := NewTimer()
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- tm.Update(1)
- }
-}
-
-func TestGetOrRegisterTimer(t *testing.T) {
- r := NewRegistry()
- NewRegisteredTimer("foo", r).Update(47)
- if tm := GetOrRegisterTimer("foo", r); 1 != tm.Count() {
- t.Fatal(tm)
- }
-}
-
-func TestTimerExtremes(t *testing.T) {
- tm := NewTimer()
- tm.Update(math.MaxInt64)
- tm.Update(0)
- if stdDev := tm.StdDev(); 4.611686018427388e+18 != stdDev {
- t.Errorf("tm.StdDev(): 4.611686018427388e+18 != %v\n", stdDev)
- }
-}
-
-func TestTimerFunc(t *testing.T) {
- tm := NewTimer()
- tm.Time(func() { time.Sleep(50e6) })
- if max := tm.Max(); 45e6 > max || max > 55e6 {
- t.Errorf("tm.Max(): 45e6 > %v || %v > 55e6\n", max, max)
- }
-}
-
-func TestTimerZero(t *testing.T) {
- tm := NewTimer()
- if count := tm.Count(); 0 != count {
- t.Errorf("tm.Count(): 0 != %v\n", count)
- }
- if min := tm.Min(); 0 != min {
- t.Errorf("tm.Min(): 0 != %v\n", min)
- }
- if max := tm.Max(); 0 != max {
- t.Errorf("tm.Max(): 0 != %v\n", max)
- }
- if mean := tm.Mean(); 0.0 != mean {
- t.Errorf("tm.Mean(): 0.0 != %v\n", mean)
- }
- if stdDev := tm.StdDev(); 0.0 != stdDev {
- t.Errorf("tm.StdDev(): 0.0 != %v\n", stdDev)
- }
- ps := tm.Percentiles([]float64{0.5, 0.75, 0.99})
- if 0.0 != ps[0] {
- t.Errorf("median: 0.0 != %v\n", ps[0])
- }
- if 0.0 != ps[1] {
- t.Errorf("75th percentile: 0.0 != %v\n", ps[1])
- }
- if 0.0 != ps[2] {
- t.Errorf("99th percentile: 0.0 != %v\n", ps[2])
- }
- if rate1 := tm.Rate1(); 0.0 != rate1 {
- t.Errorf("tm.Rate1(): 0.0 != %v\n", rate1)
- }
- if rate5 := tm.Rate5(); 0.0 != rate5 {
- t.Errorf("tm.Rate5(): 0.0 != %v\n", rate5)
- }
- if rate15 := tm.Rate15(); 0.0 != rate15 {
- t.Errorf("tm.Rate15(): 0.0 != %v\n", rate15)
- }
- if rateMean := tm.RateMean(); 0.0 != rateMean {
- t.Errorf("tm.RateMean(): 0.0 != %v\n", rateMean)
- }
-}
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/validate.sh b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/validate.sh
new file mode 100644
index 000000000..f6499982e
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/validate.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+set -e
+
+# check there are no formatting issues
+GOFMT_LINES=`gofmt -l . | wc -l | xargs`
+test $GOFMT_LINES -eq 0 || echo "gofmt needs to be run, ${GOFMT_LINES} files have issues"
+
+# run the tests for the root package
+go test .
diff --git a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/writer_test.go b/Godeps/_workspace/src/github.com/rcrowley/go-metrics/writer_test.go
deleted file mode 100644
index 1aacc2871..000000000
--- a/Godeps/_workspace/src/github.com/rcrowley/go-metrics/writer_test.go
+++ /dev/null
@@ -1,22 +0,0 @@
-package metrics
-
-import (
- "sort"
- "testing"
-)
-
-func TestMetricsSorting(t *testing.T) {
- var namedMetrics = namedMetricSlice{
- {name: "zzz"},
- {name: "bbb"},
- {name: "fff"},
- {name: "ggg"},
- }
-
- sort.Sort(namedMetrics)
- for i, name := range []string{"bbb", "fff", "ggg", "zzz"} {
- if namedMetrics[i].name != name {
- t.Fail()
- }
- }
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/README.markdown b/Godeps/_workspace/src/github.com/robertkrimen/otto/README.markdown
index 571743bf1..fe8e1bd4a 100644
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/README.markdown
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/README.markdown
@@ -20,8 +20,10 @@ Run something in the VM
Get a value out of the VM
- value, err := vm.Get("abc")
- value, _ := value.ToInteger()
+ if value, err := vm.Get("abc"); err == nil {
+ if value_int, err := value.ToInteger(); err == nil {
+ fmt.Printf("", value_int, err)
+ }
}
Set a number
@@ -221,7 +223,7 @@ the interrupt channel to do this:
Where is setTimeout/setInterval?
These timing functions are not actually part of the ECMA-262 specification.
-Typically, they belong to the `windows` object (in the browser). It would not be
+Typically, they belong to the `window` object (in the browser). It would not be
difficult to provide something like these via Go, but you probably want to wrap
otto in an event loop in that case.
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/array_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/array_test.go
deleted file mode 100644
index 06f481bd4..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/array_test.go
+++ /dev/null
@@ -1,716 +0,0 @@
-package otto
-
-import (
- "testing"
-)
-
-func TestArray(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var abc = [ undefined, "Nothing happens." ];
- abc.length;
- `, 2)
-
- test(`
- abc = ""+[0, 1, 2, 3];
- def = [].toString();
- ghi = [null, 4, "null"].toString();
- [ abc, def, ghi ];
- `, "0,1,2,3,,,4,null")
-
- test(`new Array(0).length`, 0)
-
- test(`new Array(11).length`, 11)
-
- test(`new Array(11, 1).length`, 2)
-
- test(`
- abc = [0, 1, 2, 3];
- abc.xyzzy = "Nothing happens.";
- delete abc[1];
- var xyzzy = delete abc.xyzzy;
- [ abc, xyzzy, abc.xyzzy ];
- `, "0,,2,3,true,")
-
- test(`
- var abc = [0, 1, 2, 3, 4];
- abc.length = 2;
- abc;
- `, "0,1")
-
- test(`raise:
- [].length = 3.14159;
- `, "RangeError")
-
- test(`raise:
- new Array(3.14159);
- `, "RangeError")
-
- test(`
- Object.defineProperty(Array.prototype, "0", {
- value: 100,
- writable: false,
- configurable: true
- });
- abc = [101];
- abc.hasOwnProperty("0") && abc[0] === 101;
- `, true)
-
- test(`
- abc = [,,undefined];
- [ abc.hasOwnProperty(0), abc.hasOwnProperty(1), abc.hasOwnProperty(2) ];
- `, "false,false,true")
-
- test(`
- abc = Object.getOwnPropertyDescriptor(Array, "prototype");
- [ [ typeof Array.prototype ],
- [ abc.writable, abc.enumerable, abc.configurable ] ];
- `, "object,false,false,false")
- })
-}
-
-func TestArray_toString(t *testing.T) {
- tt(t, func() {
- {
- test(`
- Array.prototype.toString = function() {
- return "Nothing happens.";
- }
- abc = Array.prototype.toString();
- def = [].toString();
- ghi = [null, 4, "null"].toString();
-
- [ abc, def, ghi ].join(",");
- `, "Nothing happens.,Nothing happens.,Nothing happens.")
- }
-
- {
- test(`
- Array.prototype.join = undefined
- abc = Array.prototype.toString()
- def = [].toString()
- ghi = [null, 4, "null"].toString()
-
- abc + "," + def + "," + ghi;
- `, "[object Array],[object Array],[object Array]")
- }
- })
-}
-
-func TestArray_toLocaleString(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- defer mockUTC()()
-
- test(`
- [ 3.14159, "abc", undefined, new Date(0) ].toLocaleString();
- `, "3.14159,abc,,1970-01-01 00:00:00")
-
- test(`raise:
- [ { toLocaleString: undefined } ].toLocaleString();
- `, "TypeError")
- })
-}
-
-func TestArray_concat(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- abc = [0, 1, 2];
- def = [-1, -2, -3];
- ghi = abc.concat(def);
- jkl = abc.concat(def, 3, 4, 5);
- mno = def.concat(-4, -5, abc);
-
- [ ghi, jkl, mno ].join(";");
- `, "0,1,2,-1,-2,-3;0,1,2,-1,-2,-3,3,4,5;-1,-2,-3,-4,-5,0,1,2")
-
- test(`
- var abc = [,1];
- var def = abc.concat([], [,]);
-
- def.getClass = Object.prototype.toString;
-
- [ def.getClass(), typeof def[0], def[1], typeof def[2], def.length ];
- `, "[object Array],undefined,1,undefined,3")
-
- test(`
- Object.defineProperty(Array.prototype, "0", {
- value: 100,
- writable: false,
- configurable: true
- });
-
- var abc = Array.prototype.concat.call(101);
-
- var hasProperty = abc.hasOwnProperty("0");
- var instanceOfVerify = typeof abc[0] === "object";
- var verifyValue = false;
- verifyValue = abc[0] == 101;
-
- var verifyEnumerable = false;
- for (var property in abc) {
- if (property === "0" && abc.hasOwnProperty("0")) {
- verifyEnumerable = true;
- }
- }
-
- var verifyWritable = false;
- abc[0] = 12;
- verifyWritable = abc[0] === 12;
-
- var verifyConfigurable = false;
- delete abc[0];
- verifyConfigurable = abc.hasOwnProperty("0");
-
- [ hasProperty, instanceOfVerify, verifyValue, !verifyConfigurable, verifyEnumerable, verifyWritable ];
- `, "true,true,true,true,true,true")
- })
-}
-
-func TestArray_splice(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- abc = [0, 1, 2];
- def = abc.splice(1, 2, 3, 4, 5);
- ghi = [].concat(abc);
- jkl = ghi.splice(17, 21, 7, 8, 9);
- [ abc, def, ghi, jkl ].join(";");
- `, "0,3,4,5;1,2;0,3,4,5,7,8,9;")
- })
-}
-
-func TestArray_shift(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- abc = [0, 1, 2];
- def = abc.shift();
- ghi = [].concat(abc);
- jkl = abc.shift();
- mno = [].concat(abc);
- pqr = abc.shift();
- stu = [].concat(abc);
- vwx = abc.shift();
-
- [ abc, def, ghi, jkl, mno, pqr, stu, vwx ].join(";");
- `, ";0;1,2;1;2;2;;")
- })
-}
-
-func TestArray_push(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- abc = [0];
- def = abc.push(1);
- ghi = [].concat(abc);
- jkl = abc.push(2,3,4);
-
- [ abc, def, ghi, jkl ].join(";");
- `, "0,1,2,3,4;2;0,1;5")
- })
-}
-
-func TestArray_pop(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- abc = [0,1];
- def = abc.pop();
- ghi = [].concat(abc);
- jkl = abc.pop();
- mno = [].concat(abc);
- pqr = abc.pop();
-
- [ abc, def, ghi, jkl, mno, pqr ].join(";");
- `, ";1;0;0;;")
- })
-}
-
-func TestArray_slice(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- abc = [0,1,2,3];
- def = abc.slice();
- ghi = abc.slice(1);
- jkl = abc.slice(3,-1);
- mno = abc.slice(2,-1);
- pqr = abc.slice(-1, -10);
-
- [ abc, def, ghi, jkl, mno, pqr ].join(";");
- `, "0,1,2,3;0,1,2,3;1,2,3;;2;")
-
- // Array.protoype.slice is generic
- test(`
- abc = { 0: 0, 1: 1, 2: 2, 3: 3 };
- abc.length = 4;
- def = Array.prototype.slice.call(abc);
- ghi = Array.prototype.slice.call(abc,1);
- jkl = Array.prototype.slice.call(abc,3,-1);
- mno = Array.prototype.slice.call(abc,2,-1);
- pqr = Array.prototype.slice.call(abc,-1,-10);
-
- [ abc, def, ghi, jkl, pqr ].join(";");
- `, "[object Object];0,1,2,3;1,2,3;;")
- })
-}
-
-func TestArray_sliceArguments(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- (function(){
- return Array.prototype.slice.call(arguments, 1)
- })({}, 1, 2, 3);
- `, "1,2,3")
- })
-}
-
-func TestArray_unshift(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- abc = [];
- def = abc.unshift(0);
- ghi = [].concat(abc);
- jkl = abc.unshift(1,2,3,4);
-
- [ abc, def, ghi, jkl ].join(";");
- `, "1,2,3,4,0;1;0;5")
- })
-}
-
-func TestArray_reverse(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- abc = [0,1,2,3].reverse();
- def = [0,1,2].reverse();
-
- [ abc, def ];
- `, "3,2,1,0,2,1,0")
- })
-}
-
-func TestArray_sort(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- abc = [0,1,2,3].sort();
- def = [3,2,1,0].sort();
- ghi = [].sort();
- jkl = [0].sort();
- mno = [1,0].sort();
- pqr = [1,5,-10, 100, 8, 72, 401, 0.05].sort();
- stu = [1,5,-10, 100, 8, 72, 401, 0.05].sort(function(x, y){
- return x == y ? 0 : x < y ? -1 : 1
- });
-
- [ abc, def, ghi, jkl, mno, pqr, stu ].join(";");
- `, "0,1,2,3;0,1,2,3;;0;0,1;-10,0.05,1,100,401,5,72,8;-10,0.05,1,5,8,72,100,401")
-
- test(`Array.prototype.sort.length`, 1)
- })
-}
-
-func TestArray_isArray(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- [ Array.isArray.length, Array.isArray(), Array.isArray([]), Array.isArray({}) ];
- `, "1,false,true,false")
-
- test(`Array.isArray(Math)`, false)
- })
-}
-
-func TestArray_indexOf(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`['a', 'b', 'c', 'b'].indexOf('b')`, 1)
-
- test(`['a', 'b', 'c', 'b'].indexOf('b', 2)`, 3)
-
- test(`['a', 'b', 'c', 'b'].indexOf('b', -2)`, 3)
-
- test(`
- Object.prototype.indexOf = Array.prototype.indexOf;
- var abc = {0: 'a', 1: 'b', 2: 'c', length: 3};
- abc.indexOf('c');
- `, 2)
-
- test(`[true].indexOf(true, "-Infinity")`, 0)
-
- test(`
- var target = {};
- Math[3] = target;
- Math.length = 5;
- Array.prototype.indexOf.call(Math, target) === 3;
- `, true)
-
- test(`
- var _NaN = NaN;
- var abc = new Array("NaN", undefined, 0, false, null, {toString:function(){return NaN}}, "false", _NaN, NaN);
- abc.indexOf(NaN);
- `, -1)
-
- test(`
- var abc = {toString:function (){return 0}};
- var def = 1;
- var ghi = -(4/3);
- var jkl = new Array(false, undefined, null, "0", abc, -1.3333333333333, "string", -0, true, +0, def, 1, 0, false, ghi, -(4/3));
- [ jkl.indexOf(-(4/3)), jkl.indexOf(0), jkl.indexOf(-0), jkl.indexOf(1) ];
- `, "14,7,7,10")
- })
-}
-
-func TestArray_lastIndexOf(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`['a', 'b', 'c', 'b'].lastIndexOf('b')`, 3)
-
- test(`['a', 'b', 'c', 'b'].lastIndexOf('b', 2)`, 1)
-
- test(`['a', 'b', 'c', 'b'].lastIndexOf('b', -2)`, 1)
-
- test(`
- Object.prototype.lastIndexOf = Array.prototype.lastIndexOf;
- var abc = {0: 'a', 1: 'b', 2: 'c', 3: 'b', length: 4};
- abc.lastIndexOf('b');
- `, 3)
-
- test(`
- var target = {};
- Math[3] = target;
- Math.length = 5;
- [ Array.prototype.lastIndexOf.call(Math, target) === 3 ];
- `, "true")
-
- test(`
- var _NaN = NaN;
- var abc = new Array("NaN", undefined, 0, false, null, {toString:function(){return NaN}}, "false", _NaN, NaN);
- abc.lastIndexOf(NaN);
- `, -1)
-
- test(`
- var abc = {toString:function (){return 0}};
- var def = 1;
- var ghi = -(4/3);
- var jkl = new Array(false, undefined, null, "0", abc, -1.3333333333333, "string", -0, true, +0, def, 1, 0, false, ghi, -(4/3));
- [ jkl.lastIndexOf(-(4/3)), jkl.indexOf(0), jkl.indexOf(-0), jkl.indexOf(1) ];
- `, "15,7,7,10")
- })
-}
-
-func TestArray_every(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`raise: [].every()`, "TypeError")
-
- test(`raise: [].every("abc")`, "TypeError")
-
- test(`[].every(function() { return false })`, true)
-
- test(`[1,2,3].every(function() { return false })`, false)
-
- test(`[1,2,3].every(function() { return true })`, true)
-
- test(`[1,2,3].every(function(_, index) { if (index === 1) return true })`, false)
-
- test(`
- var abc = function(value, index, object) {
- return ('[object Math]' !== Object.prototype.toString.call(object));
- };
-
- Math.length = 1;
- Math[0] = 1;
- !Array.prototype.every.call(Math, abc);
- `, true)
-
- test(`
- var def = false;
-
- var abc = function(value, index, object) {
- def = true;
- return this === Math;
- };
-
- [11].every(abc, Math) && def;
- `, true)
-
- test(`
- var def = false;
-
- var abc = function(value, index, object) {
- def = true;
- return Math;
- };
-
- [11].every(abc) && def;
- `, true)
- })
-}
-
-func TestArray_some(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`raise: [].some("abc")`, "TypeError")
-
- test(`[].some(function() { return true })`, false)
-
- test(`[1,2,3].some(function() { return false })`, false)
-
- test(`[1,2,3].some(function() { return true })`, true)
-
- test(`[1,2,3].some(function(_, index) { if (index === 1) return true })`, true)
-
- test(`
- var abc = function(value, index, object) {
- return ('[object Math]' !== Object.prototype.toString.call(object));
- };
-
- Math.length = 1;
- Math[0] = 1;
- !Array.prototype.some.call(Math, abc);
- `, true)
-
- test(`
- var abc = function(value, index, object) {
- return this === Math;
- };
-
- [11].some(abc, Math);
- `, true)
-
- test(`
- var abc = function(value, index, object) {
- return Math;
- };
-
- [11].some(abc);
- `, true)
- })
-}
-
-func TestArray_forEach(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`raise: [].forEach("abc")`, "TypeError")
-
- test(`
- var abc = 0;
- [].forEach(function(value) {
- abc += value;
- });
- abc;
- `, 0)
-
- test(`
- abc = 0;
- var def = [];
- [1,2,3].forEach(function(value, index) {
- abc += value;
- def.push(index);
- });
- [ abc, def ];
- `, "6,0,1,2")
-
- test(`
- var def = false;
- var abc = function(value, index, object) {
- def = ('[object Math]' === Object.prototype.toString.call(object));
- };
-
- Math.length = 1;
- Math[0] = 1;
- Array.prototype.forEach.call(Math, abc);
- def;
- `, true)
-
- test(`
- var def = false;
- var abc = function(value, index, object) {
- def = this === Math;
- };
-
- [11].forEach(abc, Math);
- def;
- `, true)
- })
-}
-
-func TestArray_indexing(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var abc = new Array(0, 1);
- var def = abc.length;
- abc[4294967296] = 10; // 2^32 => 0
- abc[4294967297] = 11; // 2^32+1 => 1
- [ def, abc.length, abc[0], abc[1], abc[4294967296] ];
- `, "2,2,0,1,10")
-
- test(`
- abc = new Array(0, 1);
- def = abc.length;
- abc[4294967295] = 10;
- var ghi = abc.length;
- abc[4294967299] = 12;
- var jkl = abc.length;
- abc[4294967294] = 11;
- [ def, ghi, jkl, abc.length, abc[4294967295], abc[4294967299] ];
- `, "2,2,2,4294967295,10,12")
- })
-}
-
-func TestArray_map(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`raise: [].map("abc")`, "TypeError")
-
- test(`[].map(function() { return 1 }).length`, 0)
-
- test(`[1,2,3].map(function(value) { return value * value })`, "1,4,9")
-
- test(`[1,2,3].map(function(value) { return 1 })`, "1,1,1")
-
- test(`
- var abc = function(value, index, object) {
- return ('[object Math]' === Object.prototype.toString.call(object));
- };
-
- Math.length = 1;
- Math[0] = 1;
- Array.prototype.map.call(Math, abc)[0];
- `, true)
-
- test(`
- var abc = function(value, index, object) {
- return this === Math;
- };
-
- [11].map(abc, Math)[0];
- `, true)
- })
-}
-
-func TestArray_filter(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`raise: [].filter("abc")`, "TypeError")
-
- test(`[].filter(function() { return 1 }).length`, 0)
-
- test(`[1,2,3].filter(function() { return false }).length`, 0)
-
- test(`[1,2,3].filter(function() { return true })`, "1,2,3")
- })
-}
-
-func TestArray_reduce(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`raise: [].reduce("abc")`, "TypeError")
-
- test(`raise: [].reduce(function() {})`, "TypeError")
-
- test(`[].reduce(function() {}, 0)`, 0)
-
- test(`[].reduce(function() {}, undefined)`, "undefined")
-
- test(`['a','b','c'].reduce(function(result, value) { return result+', '+value })`, "a, b, c")
-
- test(`[1,2,3].reduce(function(result, value) { return result + value }, 4)`, 10)
-
- test(`[1,2,3].reduce(function(result, value) { return result + value })`, 6)
- })
-}
-
-func TestArray_reduceRight(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`raise: [].reduceRight("abc")`, "TypeError")
-
- test(`raise: [].reduceRight(function() {})`, "TypeError")
-
- test(`[].reduceRight(function() {}, 0)`, 0)
-
- test(`[].reduceRight(function() {}, undefined)`, "undefined")
-
- test(`['a','b','c'].reduceRight(function(result, value) { return result+', '+value })`, "c, b, a")
-
- test(`[1,2,3].reduceRight(function(result, value) { return result + value }, 4)`, 10)
-
- test(`[1,2,3].reduceRight(function(result, value) { return result + value })`, 6)
- })
-}
-
-func TestArray_defineOwnProperty(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var abc = [];
- Object.defineProperty(abc, "length", {
- writable: false
- });
- abc.length;
- `, 0)
-
- test(`raise:
- var abc = [];
- var exception;
- Object.defineProperty(abc, "length", {
- writable: false
- });
- Object.defineProperty(abc, "length", {
- writable: true
- });
- `, "TypeError")
- })
-}
-
-func TestArray_new(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var abc = new Array(null);
- var def = new Array(undefined);
- [ abc.length, abc[0] === null, def.length, def[0] === undefined ]
- `, "1,true,1,true")
-
- test(`
- var abc = new Array(new Number(0));
- var def = new Array(new Number(4294967295));
- [ abc.length, typeof abc[0], abc[0] == 0, def.length, typeof def[0], def[0] == 4294967295 ]
- `, "1,object,true,1,object,true")
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/bug_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/bug_test.go
deleted file mode 100644
index 5e4d90bae..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/bug_test.go
+++ /dev/null
@@ -1,617 +0,0 @@
-package otto
-
-import (
- "testing"
- "time"
-)
-
-func Test_262(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- // 11.13.1-1-1
- test(`raise:
- eval("42 = 42;");
- `, "ReferenceError: Invalid left-hand side in assignment")
- })
-}
-
-func Test_issue5(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`'abc' === 'def'`, false)
- test(`'\t' === '\r'`, false)
- })
-}
-
-func Test_issue13(t *testing.T) {
- tt(t, func() {
- test, tester := test()
- vm := tester.vm
-
- value, err := vm.ToValue(map[string]interface{}{
- "string": "Xyzzy",
- "number": 42,
- "array": []string{"def", "ghi"},
- })
- if err != nil {
- t.Error(err)
- t.FailNow()
- }
-
- fn, err := vm.Object(`
- (function(value){
- return ""+[value.string, value.number, value.array]
- })
- `)
- if err != nil {
- t.Error(err)
- t.FailNow()
- }
-
- result, err := fn.Value().Call(fn.Value(), value)
- if err != nil {
- t.Error(err)
- t.FailNow()
- }
- is(result.string(), "Xyzzy,42,def,ghi")
-
- anything := struct {
- Abc interface{}
- }{
- Abc: map[string]interface{}{
- "def": []interface{}{
- []interface{}{
- "a", "b", "c", "", "d", "e",
- },
- map[string]interface{}{
- "jkl": "Nothing happens.",
- },
- },
- "ghi": -1,
- },
- }
-
- vm.Set("anything", anything)
- test(`
- [
- anything,
- "~",
- anything.Abc,
- "~",
- anything.Abc.def,
- "~",
- anything.Abc.def[1].jkl,
- "~",
- anything.Abc.ghi,
- ];
- `, "[object Object],~,[object Object],~,a,b,c,,d,e,[object Object],~,Nothing happens.,~,-1")
- })
-}
-
-func Test_issue16(t *testing.T) {
- tt(t, func() {
- test, vm := test()
-
- test(`
- var def = {
- "abc": ["abc"],
- "xyz": ["xyz"]
- };
- def.abc.concat(def.xyz);
- `, "abc,xyz")
-
- vm.Set("ghi", []string{"jkl", "mno"})
-
- test(`
- def.abc.concat(def.xyz).concat(ghi);
- `, "abc,xyz,jkl,mno")
-
- test(`
- ghi.concat(def.abc.concat(def.xyz));
- `, "jkl,mno,abc,xyz")
-
- vm.Set("pqr", []interface{}{"jkl", 42, 3.14159, true})
-
- test(`
- pqr.concat(ghi, def.abc, def, def.xyz);
- `, "jkl,42,3.14159,true,jkl,mno,abc,[object Object],xyz")
-
- test(`
- pqr.concat(ghi, def.abc, def, def.xyz).length;
- `, 9)
- })
-}
-
-func Test_issue21(t *testing.T) {
- tt(t, func() {
- vm1 := New()
- vm1.Run(`
- abc = {}
- abc.ghi = "Nothing happens.";
- var jkl = 0;
- abc.def = function() {
- jkl += 1;
- return 1;
- }
- `)
- abc, err := vm1.Get("abc")
- is(err, nil)
-
- vm2 := New()
- vm2.Set("cba", abc)
- _, err = vm2.Run(`
- var pqr = 0;
- cba.mno = function() {
- pqr -= 1;
- return 1;
- }
- cba.def();
- cba.def();
- cba.def();
- `)
- is(err, nil)
-
- jkl, err := vm1.Get("jkl")
- is(err, nil)
- is(jkl, 3)
-
- _, err = vm1.Run(`
- abc.mno();
- abc.mno();
- abc.mno();
- `)
- is(err, nil)
-
- pqr, err := vm2.Get("pqr")
- is(err, nil)
- is(pqr, -3)
- })
-}
-
-func Test_issue24(t *testing.T) {
- tt(t, func() {
- _, vm := test()
-
- {
- vm.Set("abc", []string{"abc", "def", "ghi"})
- value, err := vm.Get("abc")
- is(err, nil)
- export, _ := value.Export()
- {
- value, valid := export.([]string)
- is(valid, true)
-
- is(value[0], "abc")
- is(value[2], "ghi")
- }
- }
-
- {
- vm.Set("abc", [...]string{"abc", "def", "ghi"})
- value, err := vm.Get("abc")
- is(err, nil)
- export, _ := value.Export()
- {
- value, valid := export.([3]string)
- is(valid, true)
-
- is(value[0], "abc")
- is(value[2], "ghi")
- }
- }
-
- {
- vm.Set("abc", &[...]string{"abc", "def", "ghi"})
- value, err := vm.Get("abc")
- is(err, nil)
- export, _ := value.Export()
- {
- value, valid := export.(*[3]string)
- is(valid, true)
-
- is(value[0], "abc")
- is(value[2], "ghi")
- }
- }
-
- {
- vm.Set("abc", map[int]string{0: "abc", 1: "def", 2: "ghi"})
- value, err := vm.Get("abc")
- is(err, nil)
- export, _ := value.Export()
- {
- value, valid := export.(map[int]string)
- is(valid, true)
-
- is(value[0], "abc")
- is(value[2], "ghi")
- }
- }
-
- {
- vm.Set("abc", _abcStruct{Abc: true, Ghi: "Nothing happens."})
- value, err := vm.Get("abc")
- is(err, nil)
- export, _ := value.Export()
- {
- value, valid := export.(_abcStruct)
- is(valid, true)
-
- is(value.Abc, true)
- is(value.Ghi, "Nothing happens.")
- }
- }
-
- {
- vm.Set("abc", &_abcStruct{Abc: true, Ghi: "Nothing happens."})
- value, err := vm.Get("abc")
- is(err, nil)
- export, _ := value.Export()
- {
- value, valid := export.(*_abcStruct)
- is(valid, true)
-
- is(value.Abc, true)
- is(value.Ghi, "Nothing happens.")
- }
- }
- })
-}
-
-func Test_issue39(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var abc = 0, def = [], ghi = function() {
- if (abc < 10) return ++abc;
- return undefined;
- }
- for (var jkl; (jkl = ghi());) def.push(jkl);
- def;
- `, "1,2,3,4,5,6,7,8,9,10")
-
- test(`
- var abc = ["1", "2", "3", "4"];
- var def = [];
- for (var ghi; (ghi = abc.shift());) {
- def.push(ghi);
- }
- def;
- `, "1,2,3,4")
- })
-}
-
-func Test_issue64(t *testing.T) {
- tt(t, func() {
- test, vm := test()
-
- defer mockTimeLocal(time.UTC)()
-
- abc := map[string]interface{}{
- "time": time.Unix(0, 0),
- }
- vm.Set("abc", abc)
-
- def := struct {
- Public string
- private string
- }{
- "Public", "private",
- }
- vm.Set("def", def)
-
- test(`"sec" in abc.time`, false)
-
- test(`
- [ "Public" in def, "private" in def, def.Public, def.private ];
- `, "true,false,Public,")
-
- test(`JSON.stringify(abc)`, `{"time":"1970-01-01T00:00:00Z"}`)
- })
-}
-
-func Test_issue73(t *testing.T) {
- tt(t, func() {
- test, vm := test()
-
- vm.Set("abc", [4]int{3, 2, 1, 0})
-
- test(`
- var def = [ 0, 1, 2, 3 ];
- JSON.stringify(def) + JSON.stringify(abc);
- `, "[0,1,2,3][3,2,1,0]")
- })
-}
-
-func Test_7_3_1(t *testing.T) {
- tt(t, func() {
- test(`
- eval("var test7_3_1\u2028abc = 66;");
- [ abc, typeof test7_3_1 ];
- `, "66,undefined")
- })
-}
-
-func Test_7_3_3(t *testing.T) {
- tt(t, func() {
- test(`raise:
- eval("//\u2028 =;");
- `, "SyntaxError: Unexpected token =")
- })
-}
-
-func Test_S7_3_A2_1_T1(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`raise:
- eval("'\u000Astr\u000Aing\u000A'")
- `, "SyntaxError: Unexpected token ILLEGAL")
- })
-}
-
-func Test_S7_8_3_A2_1_T1(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- [ .0 === 0.0, .0, .1 === 0.1, .1 ]
- `, "true,0,true,0.1")
- })
-}
-
-func Test_S7_8_4_A4_2_T3(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- "\a"
- `, "a")
- })
-}
-
-func Test_S7_9_A1(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var def;
- abc: for (var i = 0; i <= 0; i++) {
- for (var j = 0; j <= 1; j++) {
- if (j === 0) {
- continue abc;
- } else {
- def = true;
- }
- }
- }
- [ def, i, j ];
- `, ",1,0")
- })
-}
-
-func Test_S7_9_A3(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- (function(){
- return
- 1;
- })()
- `, "undefined")
- })
-}
-
-func Test_7_3_10(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- eval("var \u0061\u0062\u0063 = 3.14159;");
- abc;
- `, 3.14159)
-
- test(`
- abc = undefined;
- eval("var \\u0061\\u0062\\u0063 = 3.14159;");
- abc;
- `, 3.14159)
- })
-}
-
-func Test_bug(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- // 10.4.2-1-5
- test(`
- "abc\
-def"
- `, "abcdef")
-
- test(`
- eval("'abc';\
- 'def'")
- `, "def")
-
- // S12.6.1_A10
- test(`
- var abc = 0;
- do {
- if(typeof(def) === "function"){
- abc = -1;
- break;
- } else {
- abc = 1;
- break;
- }
- } while(function def(){});
- abc;
- `, 1)
-
- // S12.7_A7
- test(`raise:
- abc:
- while (true) {
- eval("continue abc");
- }
- `, "SyntaxError: Undefined label 'abc'")
-
- // S15.1.2.1_A3.3_T3
- test(`raise:
- eval("return");
- `, "SyntaxError: Illegal return statement")
-
- // 15.2.3.3-2-33
- test(`
- var abc = { "AB\n\\cd": 1 };
- Object.getOwnPropertyDescriptor(abc, "AB\n\\cd").value;
- `, 1)
-
- // S15.3_A2_T1
- test(`raise:
- Function.call(this, "var x / = 1;");
- `, "SyntaxError: Unexpected token /")
-
- // ?
- test(`
- (function(){
- var abc = [];
- (function(){
- abc.push(0);
- abc.push(1);
- })(undefined);
- if ((function(){ return true; })()) {
- (function(){
- abc.push(2);
- })();
- }
- return abc;
- })();
- `, "0,1,2")
-
- if false {
- // 15.9.5.43-0-10
- // Should be an invalid date
- test(`
- date = new Date(1970, 0, -99999999, 0, 0, 0, 1);
- `, "")
- }
-
- // S7.8.3_A1.2_T1
- test(`
- [ 0e1, 1e1, 2e1, 3e1, 4e1, 5e1, 6e1, 7e1, 8e1, 9e1 ];
- `, "0,10,20,30,40,50,60,70,80,90")
-
- // S15.10.2.7_A3_T2
- test(`
- var abc = /\s+abc\s+/.exec("\t abc def");
- [ abc.length, abc.index, abc.input, abc ];
- `, "1,0,\t abc def,\t abc ")
- })
-}
-
-func Test_issue79(t *testing.T) {
- tt(t, func() {
- test, vm := test()
-
- vm.Set("abc", []_abcStruct{
- {
- Ghi: "一",
- Def: 1,
- },
- {
- Def: 3,
- Ghi: "三",
- },
- {
- Def: 2,
- Ghi: "二",
- },
- {
- Def: 4,
- Ghi: "四",
- },
- })
-
- test(`
- abc.sort(function(a,b){ return b.Def-a.Def });
- def = [];
- for (i = 0; i < abc.length; i++) {
- def.push(abc[i].String())
- }
- def;
- `, "四,三,二,一")
- })
-}
-
-func Test_issue80(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- JSON.stringify([
- 1401868959,
- 14018689591,
- 140186895901,
- 1401868959001,
- 14018689590001,
- 140186895900001,
- 1401868959000001,
- 1401868959000001.5,
- 14018689590000001,
- 140186895900000001,
- 1401868959000000001,
- 14018689590000000001,
- 140186895900000000001,
- 140186895900000000001.5
- ]);
- `, "[1401868959,14018689591,140186895901,1401868959001,14018689590001,140186895900001,1401868959000001,1.4018689590000015e+15,14018689590000001,140186895900000001,1401868959000000001,1.401868959e+19,1.401868959e+20,1.401868959e+20]")
- })
-}
-
-func Test_issue87(t *testing.T) {
- tt(t, func() {
- test, vm := test()
-
- test(`
- var def = 0;
- abc: {
- for (;;) {
- def = !1;
- break abc;
- }
- def = !0;
- }
- def;
- `, false)
-
- _, err := vm.Run(`
-/*
-CryptoJS v3.1.2
-code.google.com/p/crypto-js
-(c) 2009-2013 by Jeff Mott. All rights reserved.
-code.google.com/p/crypto-js/wiki/License
-*/
-var CryptoJS=CryptoJS||function(h,s){var f={},g=f.lib={},q=function(){},m=g.Base={extend:function(a){q.prototype=this;var c=new q;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}},
-r=g.WordArray=m.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=s?c:4*a.length},toString:function(a){return(a||k).stringify(this)},concat:function(a){var c=this.words,d=a.words,b=this.sigBytes;a=a.sigBytes;this.clamp();if(b%4)for(var e=0;e<a;e++)c[b+e>>>2]|=(d[e>>>2]>>>24-8*(e%4)&255)<<24-8*((b+e)%4);else if(65535<d.length)for(e=0;e<a;e+=4)c[b+e>>>2]=d[e>>>2];else c.push.apply(c,d);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<<
-32-8*(c%4);a.length=h.ceil(c/4)},clone:function(){var a=m.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],d=0;d<a;d+=4)c.push(4294967296*h.random()|0);return new r.init(c,a)}}),l=f.enc={},k=l.Hex={stringify:function(a){var c=a.words;a=a.sigBytes;for(var d=[],b=0;b<a;b++){var e=c[b>>>2]>>>24-8*(b%4)&255;d.push((e>>>4).toString(16));d.push((e&15).toString(16))}return d.join("")},parse:function(a){for(var c=a.length,d=[],b=0;b<c;b+=2)d[b>>>3]|=parseInt(a.substr(b,
-2),16)<<24-4*(b%8);return new r.init(d,c/2)}},n=l.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var d=[],b=0;b<a;b++)d.push(String.fromCharCode(c[b>>>2]>>>24-8*(b%4)&255));return d.join("")},parse:function(a){for(var c=a.length,d=[],b=0;b<c;b++)d[b>>>2]|=(a.charCodeAt(b)&255)<<24-8*(b%4);return new r.init(d,c)}},j=l.Utf8={stringify:function(a){try{return decodeURIComponent(escape(n.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return n.parse(unescape(encodeURIComponent(a)))}},
-u=g.BufferedBlockAlgorithm=m.extend({reset:function(){this._data=new r.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=j.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,d=c.words,b=c.sigBytes,e=this.blockSize,f=b/(4*e),f=a?h.ceil(f):h.max((f|0)-this._minBufferSize,0);a=f*e;b=h.min(4*a,b);if(a){for(var g=0;g<a;g+=e)this._doProcessBlock(d,g);g=d.splice(0,a);c.sigBytes-=b}return new r.init(g,b)},clone:function(){var a=m.clone.call(this);
-a._data=this._data.clone();return a},_minBufferSize:0});g.Hasher=u.extend({cfg:m.extend(),init:function(a){this.cfg=this.cfg.extend(a);this.reset()},reset:function(){u.reset.call(this);this._doReset()},update:function(a){this._append(a);this._process();return this},finalize:function(a){a&&this._append(a);return this._doFinalize()},blockSize:16,_createHelper:function(a){return function(c,d){return(new a.init(d)).finalize(c)}},_createHmacHelper:function(a){return function(c,d){return(new t.HMAC.init(a,
-d)).finalize(c)}}});var t=f.algo={};return f}(Math);
-(function(h){for(var s=CryptoJS,f=s.lib,g=f.WordArray,q=f.Hasher,f=s.algo,m=[],r=[],l=function(a){return 4294967296*(a-(a|0))|0},k=2,n=0;64>n;){var j;a:{j=k;for(var u=h.sqrt(j),t=2;t<=u;t++)if(!(j%t)){j=!1;break a}j=!0}j&&(8>n&&(m[n]=l(h.pow(k,0.5))),r[n]=l(h.pow(k,1/3)),n++);k++}var a=[],f=f.SHA256=q.extend({_doReset:function(){this._hash=new g.init(m.slice(0))},_doProcessBlock:function(c,d){for(var b=this._hash.words,e=b[0],f=b[1],g=b[2],j=b[3],h=b[4],m=b[5],n=b[6],q=b[7],p=0;64>p;p++){if(16>p)a[p]=
-c[d+p]|0;else{var k=a[p-15],l=a[p-2];a[p]=((k<<25|k>>>7)^(k<<14|k>>>18)^k>>>3)+a[p-7]+((l<<15|l>>>17)^(l<<13|l>>>19)^l>>>10)+a[p-16]}k=q+((h<<26|h>>>6)^(h<<21|h>>>11)^(h<<7|h>>>25))+(h&m^~h&n)+r[p]+a[p];l=((e<<30|e>>>2)^(e<<19|e>>>13)^(e<<10|e>>>22))+(e&f^e&g^f&g);q=n;n=m;m=h;h=j+k|0;j=g;g=f;f=e;e=k+l|0}b[0]=b[0]+e|0;b[1]=b[1]+f|0;b[2]=b[2]+g|0;b[3]=b[3]+j|0;b[4]=b[4]+h|0;b[5]=b[5]+m|0;b[6]=b[6]+n|0;b[7]=b[7]+q|0},_doFinalize:function(){var a=this._data,d=a.words,b=8*this._nDataBytes,e=8*a.sigBytes;
-d[e>>>5]|=128<<24-e%32;d[(e+64>>>9<<4)+14]=h.floor(b/4294967296);d[(e+64>>>9<<4)+15]=b;a.sigBytes=4*d.length;this._process();return this._hash},clone:function(){var a=q.clone.call(this);a._hash=this._hash.clone();return a}});s.SHA256=q._createHelper(f);s.HmacSHA256=q._createHmacHelper(f)})(Math);
-(function(){var h=CryptoJS,s=h.enc.Utf8;h.algo.HMAC=h.lib.Base.extend({init:function(f,g){f=this._hasher=new f.init;"string"==typeof g&&(g=s.parse(g));var h=f.blockSize,m=4*h;g.sigBytes>m&&(g=f.finalize(g));g.clamp();for(var r=this._oKey=g.clone(),l=this._iKey=g.clone(),k=r.words,n=l.words,j=0;j<h;j++)k[j]^=1549556828,n[j]^=909522486;r.sigBytes=l.sigBytes=m;this.reset()},reset:function(){var f=this._hasher;f.reset();f.update(this._iKey)},update:function(f){this._hasher.update(f);return this},finalize:function(f){var g=
-this._hasher;f=g.finalize(f);g.reset();return g.finalize(this._oKey.clone().concat(f))}})})();
- `)
- is(err, nil)
-
- test(`CryptoJS.HmacSHA256("Message", "secret");`, "aa747c502a898200f9e4fa21bac68136f886a0e27aec70ba06daf2e2a5cb5597")
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_array.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_array.go
index 44bf88569..160a251c6 100644
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_array.go
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_array.go
@@ -420,7 +420,7 @@ func arraySortQuickPartition(thisObject *_object, left, right, pivot uint, compa
arraySortSwap(thisObject, pivot, right) // Right is now the pivot value
cursor := left
for index := left; index < right; index++ {
- if sortCompare(thisObject, index, right, compare) == -1 { // Compare to the pivot value
+ if sortCompare(thisObject, index, right, compare) < 0 { // Compare to the pivot value
arraySortSwap(thisObject, index, cursor)
cursor += 1
}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_test.go
deleted file mode 100644
index f5be00ab6..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_test.go
+++ /dev/null
@@ -1,136 +0,0 @@
-package otto
-
-import (
- "testing"
-)
-
-func TestString_substr(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- [
- "abc".substr(0,1), // "a"
- "abc".substr(0,2), // "ab"
- "abc".substr(0,3), // "abc"
- "abc".substr(0,4), // "abc"
- "abc".substr(0,9), // "abc"
- ];
- `, "a,ab,abc,abc,abc")
-
- test(`
- [
- "abc".substr(1,1), // "b"
- "abc".substr(1,2), // "bc"
- "abc".substr(1,3), // "bc"
- "abc".substr(1,4), // "bc"
- "abc".substr(1,9), // "bc"
- ];
- `, "b,bc,bc,bc,bc")
-
- test(`
- [
- "abc".substr(2,1), // "c"
- "abc".substr(2,2), // "c"
- "abc".substr(2,3), // "c"
- "abc".substr(2,4), // "c"
- "abc".substr(2,9), // "c"
- ];
- `, "c,c,c,c,c")
-
- test(`
- [
- "abc".substr(3,1), // ""
- "abc".substr(3,2), // ""
- "abc".substr(3,3), // ""
- "abc".substr(3,4), // ""
- "abc".substr(3,9), // ""
- ];
- `, ",,,,")
-
- test(`
- [
- "abc".substr(0), // "abc"
- "abc".substr(1), // "bc"
- "abc".substr(2), // "c"
- "abc".substr(3), // ""
- "abc".substr(9), // ""
- ];
- `, "abc,bc,c,,")
-
- test(`
- [
- "abc".substr(-9), // "abc"
- "abc".substr(-3), // "abc"
- "abc".substr(-2), // "bc"
- "abc".substr(-1), // "c"
- ];
- `, "abc,abc,bc,c")
-
- test(`
- [
- "abc".substr(-9, 1), // "a"
- "abc".substr(-3, 1), // "a"
- "abc".substr(-2, 1), // "b"
- "abc".substr(-1, 1), // "c"
- "abc".substr(-1, 2), // "c"
- ];
- `, "a,a,b,c,c")
-
- test(`"abcd".substr(3, 5)`, "d")
- })
-}
-
-func Test_builtin_escape(t *testing.T) {
- tt(t, func() {
- is(builtin_escape("abc"), "abc")
-
- is(builtin_escape("="), "%3D")
-
- is(builtin_escape("abc=%+32"), "abc%3D%25+32")
-
- is(builtin_escape("世界"), "%u4E16%u754C")
- })
-}
-
-func Test_builtin_unescape(t *testing.T) {
- tt(t, func() {
- is(builtin_unescape("abc"), "abc")
-
- is(builtin_unescape("=%3D"), "==")
-
- is(builtin_unescape("abc%3D%25+32"), "abc=%+32")
-
- is(builtin_unescape("%u4E16%u754C"), "世界")
- })
-}
-
-func TestGlobal_escape(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- [
- escape("abc"), // "abc"
- escape("="), // "%3D"
- escape("abc=%+32"), // "abc%3D%25+32"
- escape("\u4e16\u754c"), // "%u4E16%u754C"
- ];
- `, "abc,%3D,abc%3D%25+32,%u4E16%u754C")
- })
-}
-
-func TestGlobal_unescape(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- [
- unescape("abc"), // "abc"
- unescape("=%3D"), // "=="
- unescape("abc%3D%25+32"), // "abc=%+32"
- unescape("%u4E16%u754C"), // "世界"
- ];
- `, "abc,==,abc=%+32,世界")
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/clone.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/clone.go
index f79901b35..82cb0f0af 100644
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/clone.go
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/clone.go
@@ -140,11 +140,23 @@ func (clone *_clone) stash(in _stash) _stash {
func (clone *_clone) property(in _property) _property {
out := in
- if value, valid := in.value.(Value); valid {
+
+ switch value := in.value.(type) {
+ case Value:
out.value = clone.value(value)
- } else {
- panic(fmt.Errorf("in.value.(Value) != true"))
+ case _propertyGetSet:
+ p := _propertyGetSet{}
+ if value[0] != nil {
+ p[0] = clone.object(value[0])
+ }
+ if value[1] != nil {
+ p[1] = clone.object(value[1])
+ }
+ out.value = p
+ default:
+ panic(fmt.Errorf("in.value.(Value) != true; in.value is %T", in.value))
}
+
return out
}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate_expression.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate_expression.go
index 34449970e..8586a484f 100644
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate_expression.go
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate_expression.go
@@ -173,7 +173,11 @@ func (self *_runtime) cmpl_evaluate_nodeBracketExpression(node *_nodeBracketExpr
memberValue := member.resolve()
// TODO Pass in base value as-is, and defer toObject till later?
- return toValue(newPropertyReference(self, self.toObject(targetValue), memberValue.string(), false, _at(node.idx)))
+ object, err := self.objectCoerce(targetValue)
+ if err != nil {
+ panic(self.panicTypeError("Cannot access member '%s' of %s", memberValue.string(), err.Error(), _at(node.idx)))
+ }
+ return toValue(newPropertyReference(self, object, memberValue.string(), false, _at(node.idx)))
}
func (self *_runtime) cmpl_evaluate_nodeCallExpression(node *_nodeCallExpression, withArgumentList []interface{}) Value {
@@ -255,7 +259,7 @@ func (self *_runtime) cmpl_evaluate_nodeDotExpression(node *_nodeDotExpression)
// TODO Pass in base value as-is, and defer toObject till later?
object, err := self.objectCoerce(targetValue)
if err != nil {
- panic(self.panicTypeError("Cannot access member '%s' of %s", node.identifier, err.Error()))
+ panic(self.panicTypeError("Cannot access member '%s' of %s", node.identifier, err.Error(), _at(node.idx)))
}
return toValue(newPropertyReference(self, object, node.identifier, false, _at(node.idx)))
}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate_statement.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate_statement.go
index 7be158487..e16c6ac6c 100644
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate_statement.go
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_evaluate_statement.go
@@ -47,6 +47,9 @@ func (self *_runtime) cmpl_evaluate_nodeStatement(node _nodeStatement) Value {
}
case *_nodeDebuggerStatement:
+ if self.debugger != nil {
+ self.debugger(self.otto)
+ }
return emptyValue // Nothing happens.
case *_nodeDoWhileStatement:
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_test.go
deleted file mode 100644
index 34b050f00..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl_test.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package otto
-
-import (
- "testing"
-
- "github.com/robertkrimen/otto/parser"
-)
-
-func Test_cmpl(t *testing.T) {
- tt(t, func() {
- vm := New()
-
- test := func(src string, expect ...interface{}) {
- program, err := parser.ParseFile(nil, "", src, 0)
- is(err, nil)
- {
- program := cmpl_parse(program)
- value := vm.runtime.cmpl_evaluate_nodeProgram(program, false)
- if len(expect) > 0 {
- is(value, expect[0])
- }
- }
- }
-
- test(``, Value{})
-
- test(`var abc = 1; abc;`, 1)
-
- test(`var abc = 1 + 1; abc;`, 2)
-
- test(`1 + 2;`, 3)
- })
-}
-
-func TestParse_cmpl(t *testing.T) {
- tt(t, func() {
-
- test := func(src string) {
- program, err := parser.ParseFile(nil, "", src, 0)
- is(err, nil)
- is(cmpl_parse(program), "!=", nil)
- }
-
- test(``)
-
- test(`var abc = 1; abc;`)
-
- test(`
- function abc() {
- return;
- }
- `)
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/date_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/date_test.go
deleted file mode 100644
index a9c71edde..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/date_test.go
+++ /dev/null
@@ -1,481 +0,0 @@
-package otto
-
-import (
- "math"
- "testing"
- "time"
-)
-
-func mockTimeLocal(location *time.Location) func() {
- local := time.Local
- time.Local = location
- return func() {
- time.Local = local
- }
-}
-
-// Passing or failing should not be dependent on what time zone we're in
-func mockUTC() func() {
- return mockTimeLocal(time.UTC)
-}
-
-func TestDate(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- defer mockUTC()()
-
- time0 := time.Unix(1348616313, 47*1000*1000).Local()
-
- test(`Date`, "function Date() { [native code] }")
- test(`new Date(0).toUTCString()`, "Thu, 01 Jan 1970 00:00:00 UTC")
- test(`new Date(0).toGMTString()`, "Thu, 01 Jan 1970 00:00:00 GMT")
- if false {
- // TODO toLocale{Date,Time}String
- test(`new Date(0).toLocaleString()`, "")
- test(`new Date(0).toLocaleDateString()`, "")
- test(`new Date(0).toLocaleTimeString()`, "")
- }
- test(`new Date(1348616313).getTime()`, 1348616313)
- test(`new Date(1348616313).toUTCString()`, "Fri, 16 Jan 1970 14:36:56 UTC")
- test(`abc = new Date(1348616313047); abc.toUTCString()`, "Tue, 25 Sep 2012 23:38:33 UTC")
- test(`abc.getYear()`, time0.Year()-1900)
- test(`abc.getFullYear()`, time0.Year())
- test(`abc.getUTCFullYear()`, 2012)
- test(`abc.getMonth()`, int(time0.Month())-1) // Remember, the JavaScript month is 0-based
- test(`abc.getUTCMonth()`, 8)
- test(`abc.getDate()`, time0.Day())
- test(`abc.getUTCDate()`, 25)
- test(`abc.getDay()`, int(time0.Weekday()))
- test(`abc.getUTCDay()`, 2)
- test(`abc.getHours()`, time0.Hour())
- test(`abc.getUTCHours()`, 23)
- test(`abc.getMinutes()`, time0.Minute())
- test(`abc.getUTCMinutes()`, 38)
- test(`abc.getSeconds()`, time0.Second())
- test(`abc.getUTCSeconds()`, 33)
- test(`abc.getMilliseconds()`, time0.Nanosecond()/(1000*1000)) // In honor of the 47%
- test(`abc.getUTCMilliseconds()`, 47)
- _, offset := time0.Zone()
- test(`abc.getTimezoneOffset()`, offset/-60)
-
- test(`new Date("Xyzzy").getTime()`, math.NaN())
-
- test(`abc.setFullYear(2011); abc.toUTCString()`, "Sun, 25 Sep 2011 23:38:33 UTC")
- test(`new Date(12564504e5).toUTCString()`, "Sun, 25 Oct 2009 06:00:00 UTC")
- test(`new Date(2009, 9, 25).toUTCString()`, "Sun, 25 Oct 2009 00:00:00 UTC")
- test(`+(new Date(2009, 9, 25))`, 1256428800000)
-
- format := "Mon, 2 Jan 2006 15:04:05 MST"
-
- time1 := time.Unix(1256450400, 0)
- time0 = time.Date(time1.Year(), time1.Month(), time1.Day(), time1.Hour(), time1.Minute(), time1.Second(), time1.Nanosecond(), time1.Location()).UTC()
-
- time0 = time.Date(time1.Year(), time1.Month(), time1.Day(), time1.Hour(), time1.Minute(), time1.Second(), 2001*1000*1000, time1.Location()).UTC()
- test(`abc = new Date(12564504e5); abc.setMilliseconds(2001); abc.toUTCString()`, time0.Format(format))
-
- time0 = time.Date(time1.Year(), time1.Month(), time1.Day(), time1.Hour(), time1.Minute(), 61, time1.Nanosecond(), time1.Location()).UTC()
- test(`abc = new Date(12564504e5); abc.setSeconds("61"); abc.toUTCString()`, time0.Format(format))
-
- time0 = time.Date(time1.Year(), time1.Month(), time1.Day(), time1.Hour(), 61, time1.Second(), time1.Nanosecond(), time1.Location()).UTC()
- test(`abc = new Date(12564504e5); abc.setMinutes("61"); abc.toUTCString()`, time0.Format(format))
-
- time0 = time.Date(time1.Year(), time1.Month(), time1.Day(), 5, time1.Minute(), time1.Second(), time1.Nanosecond(), time1.Location()).UTC()
- test(`abc = new Date(12564504e5); abc.setHours("5"); abc.toUTCString()`, time0.Format(format))
-
- time0 = time.Date(time1.Year(), time1.Month(), 26, time1.Hour(), time1.Minute(), time1.Second(), time1.Nanosecond(), time1.Location()).UTC()
- test(`abc = new Date(12564504e5); abc.setDate("26"); abc.toUTCString()`, time0.Format(format))
-
- time0 = time.Date(time1.Year(), 10, time1.Day(), time1.Hour(), time1.Minute(), time1.Second(), time1.Nanosecond(), time1.Location()).UTC()
- test(`abc = new Date(12564504e5); abc.setMonth(9); abc.toUTCString()`, time0.Format(format))
- test(`abc = new Date(12564504e5); abc.setMonth("09"); abc.toUTCString()`, time0.Format(format))
-
- time0 = time.Date(time1.Year(), 11, time1.Day(), time1.Hour(), time1.Minute(), time1.Second(), time1.Nanosecond(), time1.Location()).UTC()
- test(`abc = new Date(12564504e5); abc.setMonth("10"); abc.toUTCString()`, time0.Format(format))
-
- time0 = time.Date(2010, time1.Month(), time1.Day(), time1.Hour(), time1.Minute(), time1.Second(), time1.Nanosecond(), time1.Location()).UTC()
- test(`abc = new Date(12564504e5); abc.setFullYear(2010); abc.toUTCString()`, time0.Format(format))
-
- test(`new Date("2001-01-01T10:01:02.000").getTime()`, 978343262000)
-
- // Date()
- test(`typeof Date()`, "string")
- test(`typeof Date(2006, 1, 2)`, "string")
-
- test(`
- abc = Object.getOwnPropertyDescriptor(Date, "parse");
- [ abc.value === Date.parse, abc.writable, abc.enumerable, abc.configurable ];
- `, "true,true,false,true")
-
- test(`
- abc = Object.getOwnPropertyDescriptor(Date.prototype, "toTimeString");
- [ abc.value === Date.prototype.toTimeString, abc.writable, abc.enumerable, abc.configurable ];
- `, "true,true,false,true")
-
- test(`
- var abc = Object.getOwnPropertyDescriptor(Date, "prototype");
- [ [ typeof Date.prototype ],
- [ abc.writable, abc.enumerable, abc.configurable ] ];
- `, "object,false,false,false")
- })
-}
-
-func TestDate_parse(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- defer mockUTC()()
-
- test(`Date.parse("2001-01-01T10:01:02.000")`, 978343262000)
-
- test(`Date.parse("2006-01-02T15:04:05.000")`, 1136214245000)
-
- test(`Date.parse("2006")`, 1136073600000)
-
- test(`Date.parse("1970-01-16T14:36:56+00:00")`, 1348616000)
-
- test(`Date.parse("1970-01-16T14:36:56.313+00:00")`, 1348616313)
-
- test(`Date.parse("1970-01-16T14:36:56.000")`, 1348616000)
-
- test(`Date.parse.length`, 1)
- })
-}
-
-func TestDate_UTC(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- defer mockUTC()()
-
- test(`Date.UTC(2009, 9, 25)`, 1256428800000)
-
- test(`Date.UTC.length`, 7)
- })
-}
-
-func TestDate_now(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- defer mockUTC()()
-
- // FIXME I think this too risky
- test(`+(""+Date.now()).substr(0, 10)`, float64(epochToInteger(timeToEpoch(time.Now()))/1000))
-
- test(`Date.now() - Date.now(1,2,3) < 24 * 60 * 60`, true)
- })
-}
-
-func TestDate_toISOString(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- defer mockUTC()()
-
- test(`new Date(0).toISOString()`, "1970-01-01T00:00:00.000Z")
- })
-}
-
-func TestDate_toJSON(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- defer mockUTC()()
-
- test(`new Date(0).toJSON()`, "1970-01-01T00:00:00.000Z")
- })
-}
-
-func TestDate_setYear(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- defer mockUTC()()
-
- test(`new Date(12564504e5).setYear(96)`, 846223200000)
-
- test(`new Date(12564504e5).setYear(1996)`, 846223200000)
-
- test(`new Date(12564504e5).setYear(2000)`, 972453600000)
- })
-}
-
-func TestDateDefaultValue(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- defer mockUTC()()
-
- test(`
- var date = new Date();
- date + 0 === date.toString() + "0";
- `, true)
- })
-}
-
-func TestDate_April1978(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- defer mockUTC()()
-
- test(`
- var abc = new Date(1978,3);
- [ abc.getYear(), abc.getMonth(), abc.valueOf() ];
- `, "78,3,260236800000")
- })
-}
-
-func TestDate_setMilliseconds(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- defer mockUTC()()
-
- test(`
- abc = new Date();
- def = abc.setMilliseconds();
- [ abc, def ];
- `, "Invalid Date,NaN")
- })
-}
-
-func TestDate_new(t *testing.T) {
- // FIXME?
- // This is probably incorrect, due to differences in Go date/time handling
- // versus ECMA date/time handling, but we'll leave this here for
- // future reference
-
- if true {
- return
- }
-
- tt(t, func() {
- test, _ := test()
-
- defer mockUTC()()
-
- test(`
- [
- new Date(1899, 11).valueOf(),
- new Date(1899, 12).valueOf(),
- new Date(1900, 0).valueOf()
- ]
- `, "-2211638400000,-2208960000000,-2208960000000")
- })
-}
-
-func TestDateComparison(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- defer mockUTC()()
-
- test(`
- var now0 = Date.now();
- var now1 = (new Date()).toString();
- [ now0 === now1, Math.abs(now0 - Date.parse(now1)) <= 1000 ];
- `, "false,true")
- })
-}
-
-func TestDate_setSeconds(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- defer mockUTC()()
-
- test(`
- abc = new Date(1980, 10);
- def = new Date(abc);
-
- abc.setSeconds(10, 12);
-
- def.setSeconds(10);
- def.setMilliseconds(12);
-
- abc.valueOf() === def.valueOf();
- `, true)
-
- test(`
- abc = new Date(1980, 10);
- def = new Date(abc);
-
- abc.setUTCSeconds(10, 12);
-
- def.setUTCSeconds(10);
- def.setUTCMilliseconds(12);
-
- abc.valueOf() === def.valueOf();
- `, true)
-
- test(`Date.prototype.setSeconds.length`, 2)
- test(`Date.prototype.setUTCSeconds.length`, 2)
- })
-}
-
-func TestDate_setMinutes(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- defer mockUTC()()
-
- test(`
- abc = new Date(1980, 10);
- def = new Date(abc);
-
- abc.setMinutes(8, 10, 12);
-
- def.setMinutes(8);
- def.setSeconds(10);
- def.setMilliseconds(12);
-
- abc.valueOf() === def.valueOf();
- `, true)
-
- test(`
- abc = new Date(1980, 10);
- def = new Date(abc);
-
- abc.setUTCMinutes(8, 10, 12);
-
- def.setUTCMinutes(8);
- def.setUTCSeconds(10);
- def.setUTCMilliseconds(12);
-
- abc.valueOf() === def.valueOf();
- `, true)
-
- test(`Date.prototype.setMinutes.length`, 3)
- test(`Date.prototype.setUTCMinutes.length`, 3)
- })
-}
-
-func TestDate_setHours(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- defer mockUTC()()
-
- test(`
- abc = new Date(1980, 10);
- def = new Date(abc);
-
- abc.setHours(6, 8, 10, 12);
-
- def.setHours(6);
- def.setMinutes(8);
- def.setSeconds(10);
- def.setMilliseconds(12);
-
- abc.valueOf() === def.valueOf();
- `, true)
-
- test(`
- abc = new Date(1980, 10);
- def = new Date(abc);
-
- abc.setUTCHours(6, 8, 10, 12);
-
- def.setUTCHours(6);
- def.setUTCMinutes(8);
- def.setUTCSeconds(10);
- def.setUTCMilliseconds(12);
-
- abc.valueOf() === def.valueOf();
- `, true)
-
- test(`Date.prototype.setHours.length`, 4)
- test(`Date.prototype.setUTCHours.length`, 4)
- })
-}
-
-func TestDate_setMonth(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- defer mockUTC()()
-
- test(`
- abc = new Date(1980, 10);
- def = new Date(abc);
-
- abc.setMonth(6, 8);
-
- def.setMonth(6);
- def.setDate(8);
-
- abc.valueOf() === def.valueOf();
- `, true)
-
- test(`
- abc = new Date(1980, 10);
- def = new Date(abc);
-
- abc.setUTCMonth(6, 8);
-
- def.setUTCMonth(6);
- def.setUTCDate(8);
-
- abc.valueOf() === def.valueOf();
- `, true)
-
- test(`Date.prototype.setMonth.length`, 2)
- test(`Date.prototype.setUTCMonth.length`, 2)
- })
-}
-
-func TestDate_setFullYear(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- defer mockUTC()()
-
- test(`
- abc = new Date(1980, 10);
- def = new Date(abc);
-
- abc.setFullYear(1981, 6, 8);
-
- def.setFullYear(1981);
- def.setMonth(6);
- def.setDate(8);
-
- abc.valueOf() === def.valueOf();
- `, true)
-
- test(`
- abc = new Date(1980, 10);
- def = new Date(abc);
-
- abc.setUTCFullYear(1981, 6, 8);
-
- def.setUTCFullYear(1981);
- def.setUTCMonth(6);
- def.setUTCDate(8);
-
- abc.valueOf() === def.valueOf();
- `, true)
-
- test(`Date.prototype.setFullYear.length`, 3)
- test(`Date.prototype.setUTCFullYear.length`, 3)
- })
-}
-
-func TestDate_setTime(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- defer mockUTC()()
-
- test(`
- var abc = new Date(1999, 6, 1);
- var def = new Date();
- def.setTime(abc.getTime());
- [ def, abc.valueOf() == def.valueOf() ];
- `, "Thu, 01 Jul 1999 00:00:00 UTC,true")
-
- test(`Date.prototype.setTime.length`, 1)
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/dbg/dbg.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/dbg/dbg.go
index 83bf6c573..8c27fa293 100644
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/dbg/dbg.go
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/dbg/dbg.go
@@ -282,7 +282,7 @@ func (self *Dbgr) getEmit() _emit {
// SetOutput will accept the following as a destination for output:
//
// *log.Logger Print*/Panic*/Fatal* of the logger
-// io.Writer -
+// io.Writer -
// nil Reset to the default output (os.Stderr)
// "log" Print*/Panic*/Fatal* via the "log" package
//
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/documentation_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/documentation_test.go
deleted file mode 100644
index 04646117f..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/documentation_test.go
+++ /dev/null
@@ -1,95 +0,0 @@
-package otto
-
-import (
- "fmt"
-)
-
-func ExampleSynopsis() {
-
- vm := New()
- vm.Run(`
- abc = 2 + 2;
- console.log("The value of abc is " + abc); // 4
- `)
-
- value, _ := vm.Get("abc")
- {
- value, _ := value.ToInteger()
- fmt.Println(value)
- }
-
- vm.Set("def", 11)
- vm.Run(`
- console.log("The value of def is " + def);
- `)
-
- vm.Set("xyzzy", "Nothing happens.")
- vm.Run(`
- console.log(xyzzy.length);
- `)
-
- value, _ = vm.Run("xyzzy.length")
- {
- value, _ := value.ToInteger()
- fmt.Println(value)
- }
-
- value, err := vm.Run("abcdefghijlmnopqrstuvwxyz.length")
- fmt.Println(value)
- fmt.Println(err)
-
- vm.Set("sayHello", func(call FunctionCall) Value {
- fmt.Printf("Hello, %s.\n", call.Argument(0).String())
- return UndefinedValue()
- })
-
- vm.Set("twoPlus", func(call FunctionCall) Value {
- right, _ := call.Argument(0).ToInteger()
- result, _ := vm.ToValue(2 + right)
- return result
- })
-
- value, _ = vm.Run(`
- sayHello("Xyzzy");
- sayHello();
-
- result = twoPlus(2.0);
- `)
- fmt.Println(value)
-
- // Output:
- // The value of abc is 4
- // 4
- // The value of def is 11
- // 16
- // 16
- // undefined
- // ReferenceError: 'abcdefghijlmnopqrstuvwxyz' is not defined
- // Hello, Xyzzy.
- // Hello, undefined.
- // 4
-}
-
-func ExampleConsole() {
-
- vm := New()
- console := map[string]interface{}{
- "log": func(call FunctionCall) Value {
- fmt.Println("console.log:", formatForConsole(call.ArgumentList))
- return UndefinedValue()
- },
- }
-
- err := vm.Set("console", console)
-
- value, err := vm.Run(`
- console.log("Hello, World.");
- `)
- fmt.Println(value)
- fmt.Println(err)
-
- // Output:
- // console.log: Hello, World.
- // undefined
- // <nil>
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/error_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/error_test.go
deleted file mode 100644
index 7f1b16af7..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/error_test.go
+++ /dev/null
@@ -1,192 +0,0 @@
-package otto
-
-import (
- "testing"
-)
-
-func TestError(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- [ Error.prototype.name, Error.prototype.message, Error.prototype.hasOwnProperty("message") ];
- `, "Error,,true")
- })
-}
-
-func TestError_instanceof(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`(new TypeError()) instanceof Error`, true)
- })
-}
-
-func TestPanicValue(t *testing.T) {
- tt(t, func() {
- test, vm := test()
-
- vm.Set("abc", func(call FunctionCall) Value {
- value, err := call.Otto.Run(`({ def: 3.14159 })`)
- is(err, nil)
- panic(value)
- })
-
- test(`
- try {
- abc();
- }
- catch (err) {
- error = err;
- }
- [ error instanceof Error, error.message, error.def ];
- `, "false,,3.14159")
- })
-}
-
-func Test_catchPanic(t *testing.T) {
- tt(t, func() {
- vm := New()
-
- _, err := vm.Run(`
- A syntax error that
- does not define
- var;
- abc;
- `)
- is(err, "!=", nil)
-
- _, err = vm.Call(`abc.def`, nil)
- is(err, "!=", nil)
- })
-}
-
-func TestErrorContext(t *testing.T) {
- tt(t, func() {
- vm := New()
-
- _, err := vm.Run(`
- undefined();
- `)
- {
- err := err.(*Error)
- is(err.message, "'undefined' is not a function")
- is(len(err.trace), 1)
- is(err.trace[0].location(), "<anonymous>:2:13")
- }
-
- _, err = vm.Run(`
- ({}).abc();
- `)
- {
- err := err.(*Error)
- is(err.message, "'abc' is not a function")
- is(len(err.trace), 1)
- is(err.trace[0].location(), "<anonymous>:2:14")
- }
-
- _, err = vm.Run(`
- ("abc").abc();
- `)
- {
- err := err.(*Error)
- is(err.message, "'abc' is not a function")
- is(len(err.trace), 1)
- is(err.trace[0].location(), "<anonymous>:2:14")
- }
-
- _, err = vm.Run(`
- var ghi = "ghi";
- ghi();
- `)
- {
- err := err.(*Error)
- is(err.message, "'ghi' is not a function")
- is(len(err.trace), 1)
- is(err.trace[0].location(), "<anonymous>:3:13")
- }
-
- _, err = vm.Run(`
- function def() {
- undefined();
- }
- function abc() {
- def();
- }
- abc();
- `)
- {
- err := err.(*Error)
- is(err.message, "'undefined' is not a function")
- is(len(err.trace), 3)
- is(err.trace[0].location(), "def (<anonymous>:3:17)")
- is(err.trace[1].location(), "abc (<anonymous>:6:17)")
- is(err.trace[2].location(), "<anonymous>:8:13")
- }
-
- _, err = vm.Run(`
- function abc() {
- xyz();
- }
- abc();
- `)
- {
- err := err.(*Error)
- is(err.message, "'xyz' is not defined")
- is(len(err.trace), 2)
- is(err.trace[0].location(), "abc (<anonymous>:3:17)")
- is(err.trace[1].location(), "<anonymous>:5:13")
- }
-
- _, err = vm.Run(`
- mno + 1;
- `)
- {
- err := err.(*Error)
- is(err.message, "'mno' is not defined")
- is(len(err.trace), 1)
- is(err.trace[0].location(), "<anonymous>:2:13")
- }
-
- _, err = vm.Run(`
- eval("xyz();");
- `)
- {
- err := err.(*Error)
- is(err.message, "'xyz' is not defined")
- is(len(err.trace), 1)
- is(err.trace[0].location(), "<anonymous>:1:1")
- }
-
- _, err = vm.Run(`
- xyzzy = "Nothing happens."
- eval("xyzzy();");
- `)
- {
- err := err.(*Error)
- is(err.message, "'xyzzy' is not a function")
- is(len(err.trace), 1)
- is(err.trace[0].location(), "<anonymous>:1:1")
- }
-
- _, err = vm.Run(`
- throw Error("xyzzy");
- `)
- {
- err := err.(*Error)
- is(err.message, "xyzzy")
- is(len(err.trace), 1)
- is(err.trace[0].location(), "<anonymous>:2:19")
- }
-
- _, err = vm.Run(`
- throw new Error("xyzzy");
- `)
- {
- err := err.(*Error)
- is(err.message, "xyzzy")
- is(len(err.trace), 1)
- is(err.trace[0].location(), "<anonymous>:2:23")
- }
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/function_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/function_test.go
deleted file mode 100644
index c10bf8592..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/function_test.go
+++ /dev/null
@@ -1,280 +0,0 @@
-package otto
-
-import (
- "testing"
-)
-
-func TestFunction(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var abc = Object.getOwnPropertyDescriptor(Function, "prototype");
- [ [ typeof Function.prototype, typeof Function.prototype.length, Function.prototype.length ],
- [ abc.writable, abc.enumerable, abc.configurable ] ];
- `, "function,number,0,false,false,false")
- })
-}
-
-func Test_argumentList2parameterList(t *testing.T) {
- tt(t, func() {
- is(argumentList2parameterList([]Value{toValue("abc, def"), toValue("ghi")}), []string{"abc", "def", "ghi"})
- })
-}
-
-func TestFunction_new(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`raise:
- new Function({});
- `, "SyntaxError: Unexpected identifier")
-
- test(`
- var abc = Function("def, ghi", "jkl", "return def+ghi+jkl");
- [ typeof abc, abc instanceof Function, abc("ab", "ba", 1) ];
- `, "function,true,abba1")
-
- test(`raise:
- var abc = {
- toString: function() { throw 1; }
- };
- var def = {
- toString: function() { throw 2; }
- };
- var ghi = new Function(abc, def);
- ghi;
- `, "1")
-
- // S15.3.2.1_A3_T10
- test(`raise:
- var abc = {
- toString: function() { return "z;x"; }
- };
- var def = "return this";
- var ghi = new Function(abc, def);
- ghi;
- `, "SyntaxError: Unexpected token ;")
-
- test(`raise:
- var abc;
- var def = "return true";
- var ghi = new Function(null, def);
- ghi;
- `, "SyntaxError: Unexpected token null")
- })
-}
-
-func TestFunction_apply(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`Function.prototype.apply.length`, 2)
- test(`String.prototype.substring.apply("abc", [1, 11])`, "bc")
- })
-}
-
-func TestFunction_call(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`Function.prototype.call.length`, 1)
- test(`String.prototype.substring.call("abc", 1, 11)`, "bc")
- })
-}
-
-func TestFunctionArguments(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- // Should not be able to delete arguments
- test(`
- function abc(def, arguments){
- delete def;
- return def;
- }
- abc(1);
- `, 1)
-
- // Again, should not be able to delete arguments
- test(`
- function abc(def){
- delete def;
- return def;
- }
- abc(1);
- `, 1)
-
- // Test typeof of a function argument
- test(`
- function abc(def, ghi, jkl){
- return typeof jkl
- }
- abc("1st", "2nd", "3rd", "4th", "5th");
- `, "string")
-
- test(`
- function abc(def, ghi, jkl){
- arguments[0] = 3.14;
- arguments[1] = 'Nothing happens';
- arguments[2] = 42;
- if (3.14 === def && 'Nothing happens' === ghi && 42 === jkl)
- return true;
- }
- abc(-1, 4.2, 314);
- `, true)
- })
-}
-
-func TestFunctionDeclarationInFunction(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- // Function declarations happen AFTER parameter/argument declarations
- // That is, a function declared within a function will shadow/overwrite
- // declared parameters
-
- test(`
- function abc(def){
- return def;
- function def(){
- return 1;
- }
- }
- typeof abc();
- `, "function")
- })
-}
-
-func TestArguments_defineOwnProperty(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var abc;
- var def = true;
- var ghi = {};
- (function (a, b, c) {
- Object.defineProperty(arguments, "0", {
- value: 42,
- writable: false,
- enumerable: false,
- configurable: false
- });
- Object.defineProperty(arguments, "1", {
- value: 3.14,
- configurable: true,
- enumerable: true
- });
- abc = Object.getOwnPropertyDescriptor(arguments, "0");
- for (var name in arguments) {
- ghi[name] = (ghi[name] || 0) + 1;
- if (name === "0") {
- def = false;
- }
- }
- }(0, 1, 2));
- [ abc.value, abc.writable, abc.enumerable, abc.configurable, def, ghi["1"] ];
- `, "42,false,false,false,true,1")
- })
-}
-
-func TestFunction_bind(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- defer mockUTC()()
-
- test(`
- abc = function(){
- return "abc";
- };
- def = abc.bind();
- [ typeof def.prototype, typeof def.hasOwnProperty, def.hasOwnProperty("caller"), def.hasOwnProperty("arguments"), def() ];
- `, "object,function,true,true,abc")
-
- test(`
- abc = function(){
- return arguments[1];
- };
- def = abc.bind(undefined, "abc");
- ghi = abc.bind(undefined, "abc", "ghi");
- [ def(), def("def"), ghi("def") ];
- `, ",def,ghi")
-
- test(`
- var abc = function () {};
- var ghi;
- try {
- Object.defineProperty(Function.prototype, "xyzzy", {
- value: 1001,
- writable: true,
- enumerable: true,
- configurable: true
- });
- var def = abc.bind({});
- ghi = !def.hasOwnProperty("xyzzy") && ghi.xyzzy === 1001;
- } finally {
- delete Function.prototype.xyzzy;
- }
- [ ghi ];
- `, "true")
-
- test(`
- var abc = function (def, ghi) {};
- var jkl = abc.bind({});
- var mno = abc.bind({}, 1, 2);
- [ jkl.length, mno.length ];
- `, "2,0")
-
- test(`raise:
- Math.bind();
- `, "TypeError: 'bind' is not a function")
-
- test(`
- function construct(fn, arguments) {
- var bound = Function.prototype.bind.apply(fn, [null].concat(arguments));
- return new bound();
- }
- var abc = construct(Date, [1957, 4, 27]);
- Object.prototype.toString.call(abc);
- `, "[object Date]")
-
- test(`
- var fn = function (x, y, z) {
- var result = {};
- result.abc = x + y + z;
- result.def = arguments[0] === "a" && arguments.length === 3;
- return result;
- };
- var newFn = Function.prototype.bind.call(fn, {}, "a", "b", "c");
- var result = new newFn();
- [ result.hasOwnProperty("abc"), result.hasOwnProperty("def"), result.abc, result.def ];
- `, "true,true,abc,true")
-
- test(`
- abc = function(){
- return "abc";
- };
- def = abc.bind();
- def.toString();
- `, "function () { [native code] }")
- })
-}
-
-func TestFunction_toString(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`raise:
- Function.prototype.toString.call(undefined);
- `, "TypeError")
-
- test(`
- abc = function() { return -1 ;
-}
- 1;
- abc.toString();
- `, "function() { return -1 ;\n}")
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/global_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/global_test.go
deleted file mode 100644
index 9257b58c3..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/global_test.go
+++ /dev/null
@@ -1,355 +0,0 @@
-package otto
-
-import (
- "fmt"
- "math"
- "strings"
- "testing"
-)
-
-func TestGlobal(t *testing.T) {
- tt(t, func() {
- test, vm := test()
-
- runtime := vm.vm.runtime
-
- {
- call := func(object interface{}, src string, argumentList ...interface{}) Value {
- var tgt *Object
- switch object := object.(type) {
- case Value:
- tgt = object.Object()
- case *Object:
- tgt = object
- case *_object:
- tgt = toValue_object(object).Object()
- default:
- panic("Here be dragons.")
- }
- value, err := tgt.Call(src, argumentList...)
- is(err, nil)
- return value
- }
-
- // FIXME enterGlobalScope
- if false {
- value := runtime.scope.lexical.getBinding("Object", false)._object().call(UndefinedValue(), []Value{toValue(runtime.newObject())}, false, nativeFrame)
- is(value.IsObject(), true)
- is(value, "[object Object]")
- is(value._object().prototype == runtime.global.ObjectPrototype, true)
- is(value._object().prototype == runtime.global.Object.get("prototype")._object(), true)
- is(value._object().get("toString"), "function toString() { [native code] }")
- is(call(value.Object(), "hasOwnProperty", "hasOwnProperty"), false)
-
- is(call(value._object().get("toString")._object().prototype, "toString"), "function () { [native code] }") // TODO Is this right?
- is(value._object().get("toString")._object().get("toString"), "function toString() { [native code] }")
- is(value._object().get("toString")._object().get("toString")._object(), "function toString() { [native code] }")
-
- is(call(value._object(), "propertyIsEnumerable", "isPrototypeOf"), false)
- value._object().put("xyzzy", toValue_string("Nothing happens."), false)
- is(call(value, "propertyIsEnumerable", "isPrototypeOf"), false)
- is(call(value, "propertyIsEnumerable", "xyzzy"), true)
- is(value._object().get("xyzzy"), "Nothing happens.")
-
- is(call(runtime.scope.lexical.getBinding("Object", false), "isPrototypeOf", value), false)
- is(call(runtime.scope.lexical.getBinding("Object", false)._object().get("prototype"), "isPrototypeOf", value), true)
- is(call(runtime.scope.lexical.getBinding("Function", false), "isPrototypeOf", value), false)
-
- is(runtime.newObject().prototype == runtime.global.Object.get("prototype")._object(), true)
-
- abc := runtime.newBoolean(toValue_bool(true))
- is(toValue_object(abc), "true") // TODO Call primitive?
-
- //def := runtime.localGet("Boolean")._object().Construct(UndefinedValue(), []Value{})
- //is(def, "false") // TODO Call primitive?
- }
- }
-
- test(`new Number().constructor == Number`, true)
-
- test(`this.hasOwnProperty`, "function hasOwnProperty() { [native code] }")
-
- test(`eval.length === 1`, true)
- test(`eval.prototype === undefined`, true)
- test(`raise: new eval()`, "TypeError: function eval() { [native code] } is not a constructor")
-
- test(`
- [
- [ delete undefined, undefined ],
- [ delete NaN, NaN ],
- [ delete Infinity, Infinity ],
- ];
- `, "false,,false,NaN,false,Infinity")
-
- test(`
- Object.getOwnPropertyNames(Function('return this')()).sort();
- `, "Array,Boolean,Date,Error,EvalError,Function,Infinity,JSON,Math,NaN,Number,Object,RangeError,ReferenceError,RegExp,String,SyntaxError,TypeError,URIError,console,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,escape,eval,isFinite,isNaN,parseFloat,parseInt,undefined,unescape")
-
- // __defineGetter__,__defineSetter__,__lookupGetter__,__lookupSetter__,constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf
- test(`
- Object.getOwnPropertyNames(Object.prototype).sort();
- `, "constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf")
-
- // arguments,caller,length,name,prototype
- test(`
- Object.getOwnPropertyNames(EvalError).sort();
- `, "length,prototype")
-
- test(`
- var abc = [];
- var def = [EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError];
- for (constructor in def) {
- abc.push(def[constructor] === def[constructor].prototype.constructor);
- }
- def = [Array, Boolean, Date, Function, Number, Object, RegExp, String, SyntaxError];
- for (constructor in def) {
- abc.push(def[constructor] === def[constructor].prototype.constructor);
- }
- abc;
- `, "true,true,true,true,true,true,true,true,true,true,true,true,true,true,true")
-
- test(`
- [ Array.prototype.constructor === Array, Array.constructor === Function ];
- `, "true,true")
-
- test(`
- [ Number.prototype.constructor === Number, Number.constructor === Function ];
- `, "true,true")
-
- test(`
- [ Function.prototype.constructor === Function, Function.constructor === Function ];
- `, "true,true")
- })
-}
-
-func TestGlobalLength(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- [ Object.length, Function.length, RegExp.length, Math.length ];
- `, "1,1,2,")
- })
-}
-
-func TestGlobalError(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- [ TypeError.length, TypeError(), TypeError("Nothing happens.") ];
- `, "1,TypeError,TypeError: Nothing happens.")
-
- test(`
- [ URIError.length, URIError(), URIError("Nothing happens.") ];
- `, "1,URIError,URIError: Nothing happens.")
- })
-}
-
-func TestGlobalReadOnly(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`Number.POSITIVE_INFINITY`, math.Inf(1))
-
- test(`
- Number.POSITIVE_INFINITY = 1;
- `, 1)
-
- test(`Number.POSITIVE_INFINITY`, math.Inf(1))
-
- test(`
- Number.POSITIVE_INFINITY = 1;
- Number.POSITIVE_INFINITY;
- `, math.Inf(1))
- })
-}
-
-func Test_isNaN(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`isNaN(0)`, false)
- test(`isNaN("Xyzzy")`, true)
- test(`isNaN()`, true)
- test(`isNaN(NaN)`, true)
- test(`isNaN(Infinity)`, false)
-
- test(`isNaN.length === 1`, true)
- test(`isNaN.prototype === undefined`, true)
- })
-}
-
-func Test_isFinite(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`isFinite(0)`, true)
- test(`isFinite("Xyzzy")`, false)
- test(`isFinite()`, false)
- test(`isFinite(NaN)`, false)
- test(`isFinite(Infinity)`, false)
- test(`isFinite(new Number(451));`, true)
-
- test(`isFinite.length === 1`, true)
- test(`isFinite.prototype === undefined`, true)
- })
-}
-
-func Test_parseInt(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`parseInt("0")`, 0)
- test(`parseInt("11")`, 11)
- test(`parseInt(" 11")`, 11)
- test(`parseInt("11 ")`, 11)
- test(`parseInt(" 11 ")`, 11)
- test(`parseInt(" 11\n")`, 11)
- test(`parseInt(" 11\n", 16)`, 17)
-
- test(`parseInt("Xyzzy")`, _NaN)
-
- test(`parseInt(" 0x11\n", 16)`, 17)
- test(`parseInt("0x0aXyzzy", 16)`, 10)
- test(`parseInt("0x1", 0)`, 1)
- test(`parseInt("0x10000000000000000000", 16)`, float64(75557863725914323419136))
-
- test(`parseInt.length === 2`, true)
- test(`parseInt.prototype === undefined`, true)
- })
-}
-
-func Test_parseFloat(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`parseFloat("0")`, 0)
- test(`parseFloat("11")`, 11)
- test(`parseFloat(" 11")`, 11)
- test(`parseFloat("11 ")`, 11)
- test(`parseFloat(" 11 ")`, 11)
- test(`parseFloat(" 11\n")`, 11)
- test(`parseFloat(" 11\n", 16)`, 11)
- test(`parseFloat("11.1")`, 11.1)
-
- test(`parseFloat("Xyzzy")`, _NaN)
-
- test(`parseFloat(" 0x11\n", 16)`, 0)
- test(`parseFloat("0x0a")`, 0)
- test(`parseFloat("0x0aXyzzy")`, 0)
- test(`parseFloat("Infinity")`, _Infinity)
- test(`parseFloat("infinity")`, _NaN)
- test(`parseFloat("0x")`, 0)
- test(`parseFloat("11x")`, 11)
- test(`parseFloat("Infinity1")`, _Infinity)
-
- test(`parseFloat.length === 1`, true)
- test(`parseFloat.prototype === undefined`, true)
- })
-}
-
-func Test_encodeURI(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`encodeURI("http://example.com/ Nothing happens.")`, "http://example.com/%20Nothing%20happens.")
- test(`encodeURI("http://example.com/ _^#")`, "http://example.com/%20_%5E#")
- test(`encodeURI(String.fromCharCode("0xE000"))`, "%EE%80%80")
- test(`encodeURI(String.fromCharCode("0xFFFD"))`, "%EF%BF%BD")
- test(`raise: encodeURI(String.fromCharCode("0xDC00"))`, "URIError: URI malformed")
-
- test(`encodeURI.length === 1`, true)
- test(`encodeURI.prototype === undefined`, true)
- })
-}
-
-func Test_encodeURIComponent(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`encodeURIComponent("http://example.com/ Nothing happens.")`, "http%3A%2F%2Fexample.com%2F%20Nothing%20happens.")
- test(`encodeURIComponent("http://example.com/ _^#")`, "http%3A%2F%2Fexample.com%2F%20_%5E%23")
- })
-}
-
-func Test_decodeURI(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`decodeURI(encodeURI("http://example.com/ Nothing happens."))`, "http://example.com/ Nothing happens.")
- test(`decodeURI(encodeURI("http://example.com/ _^#"))`, "http://example.com/ _^#")
- test(`raise: decodeURI("http://example.com/ _^#%")`, "URIError: URI malformed")
- test(`raise: decodeURI("%DF%7F")`, "URIError: URI malformed")
- for _, check := range strings.Fields("+ %3B %2F %3F %3A %40 %26 %3D %2B %24 %2C %23") {
- test(fmt.Sprintf(`decodeURI("%s")`, check), check)
- }
-
- test(`decodeURI.length === 1`, true)
- test(`decodeURI.prototype === undefined`, true)
- })
-}
-
-func Test_decodeURIComponent(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`decodeURIComponent(encodeURI("http://example.com/ Nothing happens."))`, "http://example.com/ Nothing happens.")
- test(`decodeURIComponent(encodeURI("http://example.com/ _^#"))`, "http://example.com/ _^#")
-
- test(`decodeURIComponent.length === 1`, true)
- test(`decodeURIComponent.prototype === undefined`, true)
-
- test(`
- var global = Function('return this')();
- var abc = Object.getOwnPropertyDescriptor(global, "decodeURIComponent");
- [ abc.value === global.decodeURIComponent, abc.writable, abc.enumerable, abc.configurable ];
- `, "true,true,false,true")
- })
-}
-
-func TestGlobal_skipEnumeration(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var found = [];
- for (var test in this) {
- if (false ||
- test === 'NaN' ||
- test === 'undefined' ||
- test === 'Infinity' ||
- false) {
- found.push(test)
- }
- }
- found.length;
- `, 0)
-
- test(`
- var found = [];
- for (var test in this) {
- if (false ||
- test === 'Object' ||
- test === 'Function' ||
- test === 'String' ||
- test === 'Number' ||
- test === 'Array' ||
- test === 'Boolean' ||
- test === 'Date' ||
- test === 'RegExp' ||
- test === 'Error' ||
- test === 'EvalError' ||
- test === 'RangeError' ||
- test === 'ReferenceError' ||
- test === 'SyntaxError' ||
- test === 'TypeError' ||
- test === 'URIError' ||
- false) {
- found.push(test)
- }
- }
- found.length;
- `, 0)
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/json_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/json_test.go
deleted file mode 100644
index 4dd2ed7bf..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/json_test.go
+++ /dev/null
@@ -1,183 +0,0 @@
-package otto
-
-import (
- "testing"
-)
-
-func BenchmarkJSON_parse(b *testing.B) {
- vm := New()
- for i := 0; i < b.N; i++ {
- vm.Run(`JSON.parse("1")`)
- vm.Run(`JSON.parse("[1,2,3]")`)
- vm.Run(`JSON.parse('{"a":{"x":100,"y":110},"b":[10,20,30],"c":"zazazaza"}')`)
- vm.Run(`JSON.parse("[1,2,3]", function(k, v) { return undefined })`)
- }
-}
-
-func TestJSON_parse(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- JSON.parse("1");
- `, 1)
-
- test(`
- JSON.parse("null");
- `, "null") // TODO Can we make this nil?
-
- test(`
- var abc = JSON.parse('"a\uFFFFbc"');
- [ abc[0], abc[2], abc[3], abc.length ];
- `, "a,b,c,4")
-
- test(`
- JSON.parse("[1, 2, 3]");
- `, "1,2,3")
-
- test(`
- JSON.parse('{ "abc": 1, "def":2 }').abc;
- `, 1)
-
- test(`
- JSON.parse('{ "abc": { "x": 100, "y": 110 }, "def": [ 10, 20 ,30 ], "ghi": "zazazaza" }').def;
- `, "10,20,30")
-
- test(`raise:
- JSON.parse("12\t\r\n 34");
- `, "SyntaxError: invalid character '3' after top-level value")
-
- test(`
- JSON.parse("[1, 2, 3]", function() { return undefined });
- `, "undefined")
-
- test(`raise:
- JSON.parse("");
- `, "SyntaxError: unexpected end of JSON input")
-
- test(`raise:
- JSON.parse("[1, 2, 3");
- `, "SyntaxError: unexpected end of JSON input")
-
- test(`raise:
- JSON.parse("[1, 2, ; abc=10");
- `, "SyntaxError: invalid character ';' looking for beginning of value")
-
- test(`raise:
- JSON.parse("[1, 2, function(){}]");
- `, "SyntaxError: invalid character 'u' in literal false (expecting 'a')")
- })
-}
-
-func TestJSON_stringify(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- defer mockUTC()()
-
- test(`
- JSON.stringify(function(){});
- `, "undefined")
-
- test(`
- JSON.stringify(new Boolean(false));
- `, "false")
-
- test(`
- JSON.stringify({a1: {b1: [1,2,3,4], b2: {c1: 1, c2: 2}}, a2: 'a2'}, null, -5);
- `, `{"a1":{"b1":[1,2,3,4],"b2":{"c1":1,"c2":2}},"a2":"a2"}`)
-
- test(`
- JSON.stringify(undefined);
- `, "undefined")
-
- test(`
- JSON.stringify(1);
- `, "1")
-
- test(`
- JSON.stringify("abc def");
- `, "\"abc def\"")
-
- test(`
- JSON.stringify(3.14159);
- `, "3.14159")
-
- test(`
- JSON.stringify([]);
- `, "[]")
-
- test(`
- JSON.stringify([1, 2, 3]);
- `, "[1,2,3]")
-
- test(`
- JSON.stringify([true, false, null]);
- `, "[true,false,null]")
-
- test(`
- JSON.stringify({
- abc: { x: 100, y: 110 },
- def: [ 10, 20, 30 ],
- ghi: "zazazaza"
- });
- `, `{"abc":{"x":100,"y":110},"def":[10,20,30],"ghi":"zazazaza"}`)
-
- test(`
- JSON.stringify([
- 'e',
- {pluribus: 'unum'}
- ], null, '\t');
- `, "[\n\t\"e\",\n\t{\n\t\t\"pluribus\": \"unum\"\n\t}\n]")
-
- test(`
- JSON.stringify(new Date(0));
- `, `"1970-01-01T00:00:00.000Z"`)
-
- test(`
- JSON.stringify([ new Date(0) ], function(key, value){
- return this[key] instanceof Date ? 'Date(' + this[key] + ')' : value
- });
- `, `["Date(Thu, 01 Jan 1970 00:00:00 UTC)"]`)
-
- test(`
- JSON.stringify({
- abc: 1,
- def: 2,
- ghi: 3
- }, ['abc','def']);
- `, `{"abc":1,"def":2}`)
-
- test(`raise:
- var abc = {
- def: null
- };
- abc.def = abc;
- JSON.stringify(abc)
- `, "TypeError: Converting circular structure to JSON")
-
- test(`raise:
- var abc= [ null ];
- abc[0] = abc;
- JSON.stringify(abc);
- `, "TypeError: Converting circular structure to JSON")
-
- test(`raise:
- var abc = {
- def: {}
- };
- abc.def.ghi = abc;
- JSON.stringify(abc)
- `, "TypeError: Converting circular structure to JSON")
-
- test(`
- var ghi = { "pi": 3.14159 };
- var abc = {
- def: {}
- };
- abc.ghi = ghi;
- abc.def.ghi = ghi;
- JSON.stringify(abc);
- `, `{"def":{"ghi":{"pi":3.14159}},"ghi":{"pi":3.14159}}`)
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/math_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/math_test.go
deleted file mode 100644
index 499998b14..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/math_test.go
+++ /dev/null
@@ -1,303 +0,0 @@
-package otto
-
-import (
- "math"
- "testing"
-)
-
-var _NaN = math.NaN()
-var _Infinity = math.Inf(1)
-
-func TestMath_toString(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`Math.toString()`, "[object Math]")
- })
-}
-
-func TestMath_abs(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`Math.abs(NaN)`, _NaN)
- test(`Math.abs(2)`, 2)
- test(`Math.abs(-2)`, 2)
- test(`Math.abs(-Infinity)`, _Infinity)
-
- test(`Math.acos(0.5)`, 1.0471975511965976)
-
- test(`Math.abs('-1')`, 1)
- test(`Math.abs(-2)`, 2)
- test(`Math.abs(null)`, 0)
- test(`Math.abs("string")`, _NaN)
- test(`Math.abs()`, _NaN)
- })
-}
-
-func TestMath_acos(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`Math.acos(NaN)`, _NaN)
- test(`Math.acos(2)`, _NaN)
- test(`Math.acos(-2)`, _NaN)
- test(`1/Math.acos(1)`, _Infinity)
-
- test(`Math.acos(0.5)`, 1.0471975511965976)
- })
-}
-
-func TestMath_asin(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`Math.asin(NaN)`, _NaN)
- test(`Math.asin(2)`, _NaN)
- test(`Math.asin(-2)`, _NaN)
- test(`1/Math.asin(0)`, _Infinity)
- test(`1/Math.asin(-0)`, -_Infinity)
-
- test(`Math.asin(0.5)`, 0.5235987755982989)
- })
-}
-
-func TestMath_atan(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`Math.atan(NaN)`, _NaN)
- test(`1/Math.atan(0)`, _Infinity)
- test(`1/Math.atan(-0)`, -_Infinity)
- test(`Math.atan(Infinity)`, 1.5707963267948966)
- test(`Math.atan(-Infinity)`, -1.5707963267948966)
-
- // freebsd/386 1.03 => 0.4636476090008061
- // darwin 1.03 => 0.46364760900080604
- test(`Math.atan(0.5).toPrecision(10)`, "0.463647609")
- })
-}
-
-func TestMath_atan2(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`Math.atan2()`, _NaN)
- test(`Math.atan2(NaN)`, _NaN)
- test(`Math.atan2(0, NaN)`, _NaN)
-
- test(`Math.atan2(1, 0)`, 1.5707963267948966)
- test(`Math.atan2(1, -0)`, 1.5707963267948966)
-
- test(`1/Math.atan2(0, 1)`, _Infinity)
- test(`1/Math.atan2(0, 0)`, _Infinity)
- test(`Math.atan2(0, -0)`, 3.141592653589793)
- test(`Math.atan2(0, -1)`, 3.141592653589793)
-
- test(`1/Math.atan2(-0, 1)`, -_Infinity)
- test(`1/Math.atan2(-0, 0)`, -_Infinity)
- test(`Math.atan2(-0, -0)`, -3.141592653589793)
- test(`Math.atan2(-0, -1)`, -3.141592653589793)
-
- test(`Math.atan2(-1, 0)`, -1.5707963267948966)
- test(`Math.atan2(-1, -0)`, -1.5707963267948966)
-
- test(`1/Math.atan2(1, Infinity)`, _Infinity)
- test(`Math.atan2(1, -Infinity)`, 3.141592653589793)
- test(`1/Math.atan2(-1, Infinity)`, -_Infinity)
- test(`Math.atan2(-1, -Infinity)`, -3.141592653589793)
-
- test(`Math.atan2(Infinity, 1)`, 1.5707963267948966)
- test(`Math.atan2(-Infinity, 1)`, -1.5707963267948966)
-
- test(`Math.atan2(Infinity, Infinity)`, 0.7853981633974483)
- test(`Math.atan2(Infinity, -Infinity)`, 2.356194490192345)
- test(`Math.atan2(-Infinity, Infinity)`, -0.7853981633974483)
- test(`Math.atan2(-Infinity, -Infinity)`, -2.356194490192345)
- })
-}
-
-func TestMath_ceil(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`Math.ceil(NaN)`, _NaN)
- test(`Math.ceil(+0)`, 0)
- test(`1/Math.ceil(-0)`, -_Infinity)
- test(`Math.ceil(Infinity)`, _Infinity)
- test(`Math.ceil(-Infinity)`, -_Infinity)
- test(`1/Math.ceil(-0.5)`, -_Infinity)
-
- test(`Math.ceil(-11)`, -11)
- test(`Math.ceil(-0.5)`, 0)
- test(`Math.ceil(1.5)`, 2)
- })
-}
-
-func TestMath_cos(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`Math.cos(NaN)`, _NaN)
- test(`Math.cos(+0)`, 1)
- test(`Math.cos(-0)`, 1)
- test(`Math.cos(Infinity)`, _NaN)
- test(`Math.cos(-Infinity)`, _NaN)
-
- test(`Math.cos(0.5)`, 0.8775825618903728)
- })
-}
-
-func TestMath_exp(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`Math.exp(NaN)`, _NaN)
- test(`Math.exp(+0)`, 1)
- test(`Math.exp(-0)`, 1)
- test(`Math.exp(Infinity)`, _Infinity)
- test(`Math.exp(-Infinity)`, 0)
- })
-}
-
-func TestMath_floor(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`Math.floor(NaN)`, _NaN)
- test(`Math.floor(+0)`, 0)
- test(`1/Math.floor(-0)`, -_Infinity)
- test(`Math.floor(Infinity)`, _Infinity)
- test(`Math.floor(-Infinity)`, -_Infinity)
-
- test(`Math.floor(-11)`, -11)
- test(`Math.floor(-0.5)`, -1)
- test(`Math.floor(1.5)`, 1)
- })
-}
-
-func TestMath_log(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`Math.log(NaN)`, _NaN)
- test(`Math.log(-1)`, _NaN)
- test(`Math.log(+0)`, -_Infinity)
- test(`Math.log(-0)`, -_Infinity)
- test(`1/Math.log(1)`, _Infinity)
- test(`Math.log(Infinity)`, _Infinity)
-
- test(`Math.log(0.5)`, -0.6931471805599453)
- })
-}
-
-func TestMath_max(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`Math.max(-11, -1, 0, 1, 2, 3, 11)`, 11)
- })
-}
-
-func TestMath_min(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`Math.min(-11, -1, 0, 1, 2, 3, 11)`, -11)
- })
-}
-
-func TestMath_pow(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`Math.pow(0, NaN)`, _NaN)
- test(`Math.pow(0, 0)`, 1)
- test(`Math.pow(NaN, 0)`, 1)
- test(`Math.pow(0, -0)`, 1)
- test(`Math.pow(NaN, -0)`, 1)
- test(`Math.pow(NaN, 1)`, _NaN)
- test(`Math.pow(2, Infinity)`, _Infinity)
- test(`1/Math.pow(2, -Infinity)`, _Infinity)
- test(`Math.pow(1, Infinity)`, _NaN)
- test(`Math.pow(1, -Infinity)`, _NaN)
- test(`1/Math.pow(0.1, Infinity)`, _Infinity)
- test(`Math.pow(0.1, -Infinity)`, _Infinity)
- test(`Math.pow(Infinity, 1)`, _Infinity)
- test(`1/Math.pow(Infinity, -1)`, _Infinity)
- test(`Math.pow(-Infinity, 1)`, -_Infinity)
- test(`Math.pow(-Infinity, 2)`, _Infinity)
- test(`1/Math.pow(-Infinity, -1)`, -_Infinity)
- test(`1/Math.pow(-Infinity, -2)`, _Infinity)
- test(`1/Math.pow(0, 1)`, _Infinity)
- test(`Math.pow(0, -1)`, _Infinity)
- test(`1/Math.pow(-0, 1)`, -_Infinity)
- test(`1/Math.pow(-0, 2)`, _Infinity)
- test(`Math.pow(-0, -1)`, -_Infinity)
- test(`Math.pow(-0, -2)`, _Infinity)
- test(`Math.pow(-1, 0.1)`, _NaN)
-
- test(`
- [ Math.pow(-1, +Infinity), Math.pow(1, Infinity) ];
- `, "NaN,NaN")
- })
-}
-
-func TestMath_round(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`Math.round(NaN)`, _NaN)
- test(`1/Math.round(0)`, _Infinity)
- test(`1/Math.round(-0)`, -_Infinity)
- test(`Math.round(Infinity)`, _Infinity)
- test(`Math.round(-Infinity)`, -_Infinity)
- test(`1/Math.round(0.1)`, _Infinity)
- test(`1/Math.round(-0.1)`, -_Infinity)
-
- test(`Math.round(3.5)`, 4)
- test(`Math.round(-3.5)`, -3)
- })
-}
-
-func TestMath_sin(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`Math.sin(NaN)`, _NaN)
- test(`1/Math.sin(+0)`, _Infinity)
- test(`1/Math.sin(-0)`, -_Infinity)
- test(`Math.sin(Infinity)`, _NaN)
- test(`Math.sin(-Infinity)`, _NaN)
-
- test(`Math.sin(0.5)`, 0.479425538604203)
- })
-}
-
-func TestMath_sqrt(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`Math.sqrt(NaN)`, _NaN)
- test(`Math.sqrt(-1)`, _NaN)
- test(`1/Math.sqrt(+0)`, _Infinity)
- test(`1/Math.sqrt(-0)`, -_Infinity)
- test(`Math.sqrt(Infinity)`, _Infinity)
-
- test(`Math.sqrt(2)`, 1.4142135623730951)
- })
-}
-
-func TestMath_tan(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`Math.tan(NaN)`, _NaN)
- test(`1/Math.tan(+0)`, _Infinity)
- test(`1/Math.tan(-0)`, -_Infinity)
- test(`Math.tan(Infinity)`, _NaN)
- test(`Math.tan(-Infinity)`, _NaN)
-
- test(`Math.tan(0.5)`, 0.5463024898437905)
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/number_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/number_test.go
deleted file mode 100644
index 8db01cfc7..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/number_test.go
+++ /dev/null
@@ -1,165 +0,0 @@
-package otto
-
-import (
- "testing"
-)
-
-func TestNumber(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var abc = Object.getOwnPropertyDescriptor(Number, "prototype");
- [ [ typeof Number.prototype ],
- [ abc.writable, abc.enumerable, abc.configurable ] ];
- `, "object,false,false,false")
- })
-}
-
-func TestNumber_toString(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- new Number(451).toString();
- `, "451")
-
- test(`
- new Number(451).toString(10);
- `, "451")
-
- test(`
- new Number(451).toString(8);
- `, "703")
-
- test(`raise:
- new Number(451).toString(1);
- `, "RangeError: RangeError: toString() radix must be between 2 and 36")
-
- test(`raise:
- new Number(451).toString(Infinity);
- `, "RangeError: RangeError: toString() radix must be between 2 and 36")
-
- test(`
- new Number(NaN).toString()
- `, "NaN")
-
- test(`
- new Number(Infinity).toString()
- `, "Infinity")
-
- test(`
- new Number(Infinity).toString(16)
- `, "Infinity")
-
- test(`
- [
- Number.prototype.toString(undefined),
- new Number().toString(undefined),
- new Number(0).toString(undefined),
- new Number(-1).toString(undefined),
- new Number(1).toString(undefined),
- new Number(Number.NaN).toString(undefined),
- new Number(Number.POSITIVE_INFINITY).toString(undefined),
- new Number(Number.NEGATIVE_INFINITY).toString(undefined)
- ]
- `, "0,0,0,-1,1,NaN,Infinity,-Infinity")
- })
-}
-
-func TestNumber_toFixed(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`new Number(451).toFixed(2)`, "451.00")
- test(`12345.6789.toFixed()`, "12346")
- test(`12345.6789.toFixed(1)`, "12345.7")
- test(`12345.6789.toFixed(6)`, "12345.678900")
- test(`(1.23e-20).toFixed(2)`, "0.00")
- test(`2.34.toFixed(1)`, "2.3") // FIXME Wtf? "2.3"
- test(`-2.34.toFixed(1)`, -2.3) // FIXME Wtf? -2.3
- test(`(-2.34).toFixed(1)`, "-2.3")
-
- test(`raise:
- new Number("a").toFixed(Number.POSITIVE_INFINITY);
- `, "RangeError: toFixed() precision must be between 0 and 20")
-
- test(`
- [
- new Number(1e21).toFixed(),
- new Number(1e21).toFixed(0),
- new Number(1e21).toFixed(1),
- new Number(1e21).toFixed(1.1),
- new Number(1e21).toFixed(0.9),
- new Number(1e21).toFixed("1"),
- new Number(1e21).toFixed("1.1"),
- new Number(1e21).toFixed("0.9"),
- new Number(1e21).toFixed(Number.NaN),
- new Number(1e21).toFixed("some string")
- ];
- `, "1e+21,1e+21,1e+21,1e+21,1e+21,1e+21,1e+21,1e+21,1e+21,1e+21")
-
- test(`raise:
- new Number(1e21).toFixed(Number.POSITIVE_INFINITY);
- `, "RangeError: toFixed() precision must be between 0 and 20")
- })
-}
-
-func TestNumber_toExponential(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`new Number(451).toExponential(2)`, "4.51e+02")
- test(`77.1234.toExponential()`, "7.71234e+01")
- test(`77.1234.toExponential(4)`, "7.7123e+01")
- test(`77.1234.toExponential(2)`, "7.71e+01")
- test(`77 .toExponential()`, "7.7e+01")
- })
-}
-
-func TestNumber_toPrecision(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`new Number(451).toPrecision()`, "451")
- test(`new Number(451).toPrecision(1)`, "5e+02")
- test(`5.123456.toPrecision()`, "5.123456")
- test(`5.123456.toPrecision(5)`, "5.1235")
- test(`5.123456.toPrecision(2)`, "5.1")
- test(`5.123456.toPrecision(1)`, "5")
- })
-}
-
-func TestNumber_toLocaleString(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- [
- new Number(451).toLocaleString(),
- new Number(451).toLocaleString(10),
- new Number(451).toLocaleString(8)
- ];
- `, "451,451,703")
- })
-}
-
-func TestValue_number(t *testing.T) {
- tt(t, func() {
- nm := toValue(0.0).number()
- is(nm.kind, numberInteger)
-
- nm = toValue(3.14159).number()
- is(nm.kind, numberFloat)
- })
-}
-
-func Test_NaN(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- [ NaN === NaN, NaN == NaN ];
- `, "false,false")
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/object_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/object_test.go
deleted file mode 100644
index d1e90680b..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/object_test.go
+++ /dev/null
@@ -1,639 +0,0 @@
-package otto
-
-import (
- "testing"
-)
-
-func TestObject_(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- object := newObject(nil, "")
- is(object != nil, true)
-
- object.put("xyzzy", toValue("Nothing happens."), true)
- is(object.get("xyzzy"), "Nothing happens.")
-
- test(`
- var abc = Object.getOwnPropertyDescriptor(Object, "prototype");
- [ [ typeof Object.prototype, abc.writable, abc.enumerable, abc.configurable ],
- ];
- `, "object,false,false,false")
- })
-}
-
-func TestStringObject(t *testing.T) {
- tt(t, func() {
- object := New().runtime.newStringObject(toValue("xyzzy"))
- is(object.get("1"), "y")
- is(object.get("10"), "undefined")
- is(object.get("2"), "z")
- })
-}
-
-func TestObject_getPrototypeOf(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- abc = {};
- def = Object.getPrototypeOf(abc);
- ghi = Object.getPrototypeOf(def);
- [abc,def,ghi,ghi+""];
- `, "[object Object],[object Object],,null")
-
- test(`
- abc = Object.getOwnPropertyDescriptor(Object, "getPrototypeOf");
- [ abc.value === Object.getPrototypeOf, abc.writable, abc.enumerable, abc.configurable ];
- `, "true,true,false,true")
- })
-}
-
-func TestObject_new(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- [ new Object("abc"), new Object(2+2) ];
- `, "abc,4")
- })
-}
-
-func TestObject_create(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`raise: Object.create()`, "TypeError")
-
- test(`
- var abc = Object.create(null)
- var def = Object.create({x: 10, y: 20})
- var ghi = Object.create(Object.prototype)
-
- var jkl = Object.create({x: 10, y: 20}, {
- z: {
- value: 30,
- writable: true
- },
- // sum: {
- // get: function() {
- // return this.x + this.y + this.z
- // }
- // }
- });
- [ abc.prototype, def.x, def.y, ghi, jkl.x, jkl.y, jkl.z ]
- `, ",10,20,[object Object],10,20,30")
-
- test(`
- var properties = {};
- Object.defineProperty(properties, "abc", {
- value: {},
- enumerable: false
- });
- var mno = Object.create({}, properties);
- mno.hasOwnProperty("abc");
- `, false)
- })
-}
-
-func TestObject_toLocaleString(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- ({}).toLocaleString();
- `, "[object Object]")
-
- test(`
- object = {
- toString: function() {
- return "Nothing happens.";
- }
- };
- object.toLocaleString();
- `, "Nothing happens.")
- })
-}
-
-func TestObject_isExtensible(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`raise:
- Object.isExtensible();
- `, "TypeError")
-
- // FIXME terst, Why raise?
- test(`raise:
- Object.isExtensible({});
- `, true)
-
- test(`Object.isExtensible.length`, 1)
- test(`Object.isExtensible.prototype`, "undefined")
- })
-}
-
-func TestObject_preventExtensions(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`raise:
- Object.preventExtensions()
- `, "TypeError")
-
- test(`raise:
- var abc = { def: true };
- var ghi = Object.preventExtensions(abc);
- [ ghi.def === true, Object.isExtensible(abc), Object.isExtensible(ghi) ];
- `, "true,false,false")
-
- test(`
- var abc = new String();
- var def = Object.isExtensible(abc);
- Object.preventExtensions(abc);
- var ghi = false;
- try {
- Object.defineProperty(abc, "0", { value: "~" });
- } catch (err) {
- ghi = err instanceof TypeError;
- }
- [ def, ghi, abc.hasOwnProperty("0"), typeof abc[0] ];
- `, "true,true,false,undefined")
-
- test(`Object.preventExtensions.length`, 1)
- test(`Object.preventExtensions.prototype`, "undefined")
- })
-}
-
-func TestObject_isSealed(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`Object.isSealed.length`, 1)
- test(`Object.isSealed.prototype`, "undefined")
- })
-}
-
-func TestObject_seal(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`raise: Object.seal()`, "TypeError")
-
- test(`
- var abc = {a:1,b:1,c:3};
- var sealed = Object.isSealed(abc);
- Object.seal(abc);
- [sealed, Object.isSealed(abc)];
- `, "false,true")
-
- test(`
- var abc = {a:1,b:1,c:3};
- var sealed = Object.isSealed(abc);
- var caught = false;
- Object.seal(abc);
- abc.b = 5;
- Object.defineProperty(abc, "a", {value:4});
- try {
- Object.defineProperty(abc, "a", {value:42,enumerable:false});
- } catch (e) {
- caught = e instanceof TypeError;
- }
- [sealed, Object.isSealed(abc), caught, abc.a, abc.b];
- `, "false,true,true,4,5")
-
- test(`Object.seal.length`, 1)
- test(`Object.seal.prototype`, "undefined")
- })
-}
-
-func TestObject_isFrozen(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`raise: Object.isFrozen()`, "TypeError")
- test(`Object.isFrozen(Object.preventExtensions({a:1}))`, false)
- test(`Object.isFrozen({})`, false)
-
- test(`
- var abc = {};
- Object.defineProperty(abc, "def", {
- value: "def",
- writable: true,
- configurable: false
- });
- Object.preventExtensions(abc);
- !Object.isFrozen(abc);
- `, true)
-
- test(`Object.isFrozen.length`, 1)
- test(`Object.isFrozen.prototype`, "undefined")
- })
-}
-
-func TestObject_freeze(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`raise: Object.freeze()`, "TypeError")
-
- test(`
- var abc = {a:1,b:2,c:3};
- var frozen = Object.isFrozen(abc);
- Object.freeze(abc);
- abc.b = 5;
- [frozen, Object.isFrozen(abc), abc.b];
- `, "false,true,2")
-
- test(`
- var abc = {a:1,b:2,c:3};
- var frozen = Object.isFrozen(abc);
- var caught = false;
- Object.freeze(abc);
- abc.b = 5;
- try {
- Object.defineProperty(abc, "a", {value:4});
- } catch (e) {
- caught = e instanceof TypeError;
- }
- [frozen, Object.isFrozen(abc), caught, abc.a, abc.b];
- `, "false,true,true,1,2")
-
- test(`Object.freeze.length`, 1)
- test(`Object.freeze.prototype`, "undefined")
- })
-}
-
-func TestObject_defineProperty(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- (function(abc, def, ghi){
- Object.defineProperty(arguments, "0", {
- enumerable: false
- });
- return true;
- })(0, 1, 2);
- `, true)
-
- test(`
- var abc = {};
- abc.def = 3.14; // Default: writable: true, enumerable: true, configurable: true
-
- Object.defineProperty(abc, "def", {
- value: 42
- });
-
- var ghi = Object.getOwnPropertyDescriptor(abc, "def");
- [ ghi.value, ghi.writable, ghi.enumerable, ghi.configurable ];
- `, "42,true,true,true")
-
- // Test that we handle the case of DefineOwnProperty
- // where [[Writable]] is something but [[Value]] is not
- test(`
- var abc = [];
- Object.defineProperty(abc, "0", { writable: false });
- 0 in abc;
- `, true)
-
- // Test that we handle the case of DefineOwnProperty
- // where [[Writable]] is something but [[Value]] is not
- // (and the property originally had something for [[Value]]
- test(`
- abc = {
- def: 42
- };
- Object.defineProperty(abc, "def", { writable: false });
- abc.def;
- `, 42)
- })
-}
-
-func TestObject_keys(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`Object.keys({ abc:undefined, def:undefined })`, "abc,def")
-
- test(`
- function abc() {
- this.abc = undefined;
- this.def = undefined;
- }
- Object.keys(new abc())
- `, "abc,def")
-
- test(`
- function def() {
- this.ghi = undefined;
- }
- def.prototype = new abc();
- Object.keys(new def());
- `, "ghi")
-
- test(`
- var ghi = Object.create(
- {
- abc: undefined,
- def: undefined
- },
- {
- ghi: { value: undefined, enumerable: true },
- jkl: { value: undefined, enumerable: false }
- }
- );
- Object.keys(ghi);
- `, "ghi")
-
- test(`
- (function(abc, def, ghi){
- return Object.keys(arguments)
- })(undefined, undefined);
- `, "0,1")
-
- test(`
- (function(abc, def, ghi){
- return Object.keys(arguments)
- })(undefined, undefined, undefined, undefined);
- `, "0,1,2,3")
- })
-}
-
-func TestObject_getOwnPropertyNames(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`Object.getOwnPropertyNames({ abc:undefined, def:undefined })`, "abc,def")
-
- test(`
- var ghi = Object.create(
- {
- abc: undefined,
- def: undefined
- },
- {
- ghi: { value: undefined, enumerable: true },
- jkl: { value: undefined, enumerable: false }
- }
- );
- Object.getOwnPropertyNames(ghi)
- `, "ghi,jkl")
- })
-}
-
-func TestObjectGetterSetter(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`raise:
- Object.create({}, {
- abc: {
- get: function(){
- return "true";
- },
- writable: true
- }
- }).abc;
- `, "TypeError")
-
- test(`raise:
- Object.create({}, {
- abc: {
- get: function(){
- return "true";
- },
- writable: false
- }
- }).abc;
- `, "TypeError")
-
- test(`
- Object.create({}, {
- abc: {
- get: function(){
- return "true";
- }
- }
- }).abc;
- `, "true")
-
- test(`
- Object.create({xyz:true},{abc:{get:function(){return this.xyx}}}).abc;
- Object.create({
- xyz: true
- }, {
- abc: {
- get: function(){
- return this.xyz;
- }
- }
- }).abc;
- `, true)
-
- test(`
- var abc = false;
- var def = Object.create({}, {
- xyz: {
- set: function(value) {
- abc = value;
- }
- }
- });
- def.xyz = true;
- [ abc ];
- `, "true")
-
- test(`
- var abc = {};
- Object.defineProperty(abc, "def", {
- value: "xyzzy",
- configurable: true
- });
- Object.preventExtensions(abc);
- Object.defineProperty(abc, "def", {
- get: function() {
- return 5;
- }
- });
- var def = Object.getOwnPropertyDescriptor(abc, "def");
- [ abc.def, typeof def.get, typeof def.set, typeof def.value, def.configurable, def.enumerable, typeof def.writable ];
- `, "5,function,undefined,undefined,true,false,undefined")
-
- test(`
- var abc = {};
- Object.defineProperty(abc, "def", {
- get: function() {
- return 5;
- }
- configurable: true
- });
- Object.preventExtensions(abc);
- Object.defineProperty(abc, "def", {
- value: "xyzzy",
- });
- var def = Object.getOwnPropertyDescriptor(abc, "def");
- [ abc.def, typeof def.get, typeof def.set, def.value, def.configurable, def.enumerable, def.writable ];
- `, "xyzzy,undefined,undefined,xyzzy,true,false,false")
-
- test(`
- var abc = {};
-
- function _get0() {
- return 10;
- }
-
- function _set(value) {
- abc.def = value;
- }
-
- Object.defineProperty(abc, "ghi", {
- get: _get0,
- set: _set,
- configurable: true
- });
-
- function _get1() {
- return 20;
- }
-
- Object.defineProperty(abc, "ghi", {
- get: _get0
- });
-
- var descriptor = Object.getOwnPropertyDescriptor(abc, "ghi");
- [ typeof descriptor.set ];
- `, "function")
-
- test(`raise:
- var abc = [];
- Object.defineProperty(abc, "length", {
- get: function () {
- return 2;
- }
- });
- `, "TypeError")
-
- test(`
- var abc = {};
-
- var getter = function() {
- return 1;
- }
-
- Object.defineProperty(abc, "def", {
- get: getter,
- configurable: false
- });
-
- var jkl = undefined;
- try {
- Object.defineProperty(abc, "def", {
- get: undefined
- });
- }
- catch (err) {
- jkl = err;
- }
- var ghi = Object.getOwnPropertyDescriptor(abc, "def");
- [ jkl instanceof TypeError, ghi.get === getter, ghi.configurable, ghi.enumerable ];
- `, "true,true,false,false")
-
- test(`
- var abc = {};
-
- var getter = function() {
- return 1;
- };
-
- Object.defineProperty(abc, "def", {
- get: getter
- });
-
- Object.defineProperty(abc, "def", {
- set: undefined
- });
-
- var ghi = Object.getOwnPropertyDescriptor(abc, "def");
- [ ghi.get === getter, ghi.set === undefined, ghi.configurable, ghi.enumerable ];
- `, "true,true,false,false")
-
- test(`
- var abc = {};
-
- var getter = function() {
- return 1;
- };
-
- Object.defineProperty(abc, "def", {
- get: getter
- });
-
- var jkl = undefined;
- try {
- Object.defineProperty(abc, "def", {
- set: function() {}
- });
- }
- catch (err) {
- jkl = err;
- }
-
- var ghi = Object.getOwnPropertyDescriptor(abc, "def");
- [ jkl instanceof TypeError, ghi.get === getter, ghi.set, ghi.configurable, ghi.enumerable ];
- `, "true,true,,false,false")
-
- test(`
- var abc = {};
- var def = "xyzzy";
-
- Object.defineProperty(abc, "ghi", {
- get: undefined,
- set: function(value) {
- def = value;
- },
- enumerable: true,
- configurable: true
- });
-
- var hasOwn = abc.hasOwnProperty("ghi");
- var descriptor = Object.getOwnPropertyDescriptor(abc, "ghi");
-
- [ hasOwn, typeof descriptor.get ];
- `, "true,undefined")
-
- test(`
- var abc = "xyzzy";
- Object.defineProperty(Array.prototype, "abc", {
- get: function () {
- return abc;
- },
- set: function (value) {
- abc = value;
- },
- enumerable: true,
- configurable: true
- });
- var def = [];
- def.abc = 3.14159;
- [ def.hasOwnProperty("abc"), def.abc, abc ];
- `, "false,3.14159,3.14159")
- })
-}
-
-func TestProperty(t *testing.T) {
- tt(t, func() {
- property := _property{}
- property.writeOn()
- is(property.writeSet(), true)
-
- property.writeClear()
- is(property.writeSet(), false)
-
- property.writeOff()
- is(property.writeSet(), true)
-
- property.writeClear()
- is(property.writeSet(), false)
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/otto.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/otto.go
index 9de3e08c5..2ec033cbc 100644
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/otto.go
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/otto.go
@@ -296,6 +296,24 @@ func (self Otto) Run(src interface{}) (Value, error) {
return value, err
}
+// Eval will do the same thing as Run, except without leaving the current scope.
+//
+// By staying in the same scope, the code evaluated has access to everything
+// already defined in the current stack frame. This is most useful in, for
+// example, a debugger call.
+func (self Otto) Eval(src interface{}) (Value, error) {
+ if self.runtime.scope == nil {
+ self.runtime.enterGlobalScope()
+ defer self.runtime.leaveScope()
+ }
+
+ value, err := self.runtime.cmpl_eval(src)
+ if !value.safe() {
+ value = Value{}
+ }
+ return value, err
+}
+
// Get the value of the top-level binding of the given name.
//
// If there is an error (like the binding does not exist), then the value
@@ -341,6 +359,79 @@ func (self Otto) setValue(name string, value Value) {
self.runtime.globalStash.setValue(name, value, false)
}
+func (self Otto) SetDebuggerHandler(fn func(vm *Otto)) {
+ self.runtime.debugger = fn
+}
+
+// Context is a structure that contains information about the current execution
+// context.
+type Context struct {
+ Filename string
+ Line int
+ Column int
+ Callee string
+ Symbols map[string]Value
+ This Value
+ Stacktrace []string
+}
+
+// Context returns the current execution context of the vm
+func (self Otto) Context() (ctx Context) {
+ // Ensure we are operating in a scope
+ if self.runtime.scope == nil {
+ self.runtime.enterGlobalScope()
+ defer self.runtime.leaveScope()
+ }
+
+ scope := self.runtime.scope
+ frame := scope.frame
+
+ // Get location information
+ ctx.Filename = "<unknown>"
+ ctx.Callee = frame.callee
+ if frame.file != nil {
+ ctx.Filename = frame.file.Name()
+ if ctx.Filename == "" {
+ ctx.Filename = "<anonymous>"
+ }
+ ctx.Line, ctx.Column = _position(frame.file, frame.offset)
+ }
+
+ // Get the current scope this Value
+ ctx.This = toValue_object(scope.this)
+
+ // Build stacktrace (up to 10 levels deep)
+ limit := 10
+ ctx.Symbols = make(map[string]Value)
+ ctx.Stacktrace = append(ctx.Stacktrace, frame.location())
+ for limit > 0 {
+ // Get variables
+ stash := scope.lexical
+ for {
+ for _, name := range getStashProperties(stash) {
+ if _, ok := ctx.Symbols[name]; !ok {
+ ctx.Symbols[name] = stash.getBinding(name, true)
+ }
+ }
+ stash = stash.outer()
+ if stash == nil || stash.outer() == nil {
+ break
+ }
+ }
+
+ scope = scope.outer
+ if scope == nil {
+ break
+ }
+ if scope.frame.offset >= 0 {
+ ctx.Stacktrace = append(ctx.Stacktrace, scope.frame.location())
+ }
+ limit--
+ }
+
+ return
+}
+
// Call the given JavaScript with a given this and arguments.
//
// If this is nil, then some special handling takes place to determine the proper
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/otto_.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/otto_.go
index e053b54e2..304a83150 100644
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/otto_.go
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/otto_.go
@@ -20,12 +20,12 @@ func (self *_runtime) toValueArray(arguments ...interface{}) []Value {
if valueArray, ok := arguments[0].([]Value); ok {
return valueArray
}
- return []Value{toValue(arguments[0])}
+ return []Value{self.toValue(arguments[0])}
}
valueArray := make([]Value, length)
for index, value := range arguments {
- valueArray[index] = toValue(value)
+ valueArray[index] = self.toValue(value)
}
return valueArray
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/otto_error_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/otto_error_test.go
deleted file mode 100644
index 5ce358819..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/otto_error_test.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package otto
-
-import (
- "testing"
-)
-
-func TestOttoError(t *testing.T) {
- tt(t, func() {
- vm := New()
-
- _, err := vm.Run(`throw "Xyzzy"`)
- is(err, "Xyzzy")
-
- _, err = vm.Run(`throw new TypeError()`)
- is(err, "TypeError")
-
- _, err = vm.Run(`throw new TypeError("Nothing happens.")`)
- is(err, "TypeError: Nothing happens.")
-
- _, err = ToValue([]byte{})
- is(err, "TypeError: invalid value (slice): missing runtime: [] ([]uint8)")
-
- _, err = vm.Run(`
- (function(){
- return abcdef.length
- })()
- `)
- is(err, "ReferenceError: 'abcdef' is not defined")
-
- _, err = vm.Run(`
- function start() {
- }
-
- start()
-
- xyzzy()
- `)
- is(err, "ReferenceError: 'xyzzy' is not defined")
-
- _, err = vm.Run(`
- // Just a comment
-
- xyzzy
- `)
- is(err, "ReferenceError: 'xyzzy' is not defined")
-
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/otto_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/otto_test.go
deleted file mode 100644
index 2f1e1c35f..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/otto_test.go
+++ /dev/null
@@ -1,1379 +0,0 @@
-package otto
-
-import (
- "bytes"
- "io"
- "testing"
-
- "github.com/robertkrimen/otto/parser"
-)
-
-func TestOtto(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test("xyzzy = 2", 2)
-
- test("xyzzy + 2", 4)
-
- test("xyzzy += 16", 18)
-
- test("xyzzy", 18)
-
- test(`
- (function(){
- return 1
- })()
- `, 1)
-
- test(`
- (function(){
- return 1
- }).call(this)
- `, 1)
-
- test(`
- (function(){
- var result
- (function(){
- result = -1
- })()
- return result
- })()
- `, -1)
-
- test(`
- var abc = 1
- abc || (abc = -1)
- abc
- `, 1)
-
- test(`
- var abc = (function(){ 1 === 1 })();
- abc;
- `, "undefined")
- })
-}
-
-func TestFunction__(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- function abc() {
- return 1;
- };
- abc();
- `, 1)
- })
-}
-
-func TestIf(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- abc = undefined;
- def = undefined;
- if (true) abc = 1
- else abc = 2;
- if (false) {
- def = 3;
- }
- else def = 4;
-
- [ abc, def ];
- `, "1,4")
-
- test(`
- if (1) {
- abc = 1;
- }
- else {
- abc = 0;
- }
- abc;
- `, 1)
-
- test(`
- if (0) {
- abc = 1;
- }
- else {
- abc = 0;
- }
- abc;
- `, 0)
-
- test(`
- abc = 0;
- if (0) {
- abc = 1;
- }
- abc;
- `, 0)
-
- test(`
- abc = 0;
- if (abc) {
- abc = 1;
- }
- abc;
- `, 0)
- })
-}
-
-func TestSequence(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- 1, 2, 3;
- `, 3)
- })
-}
-
-func TestCall(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- Math.pow(3, 2);
- `, 9)
- })
-}
-
-func TestMember(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- abc = [ 0, 1, 2 ];
- def = {
- "abc": 0,
- "def": 1,
- "ghi": 2,
- };
- [ abc[2], def.abc, abc[1], def.def ];
- `, "2,0,1,1")
- })
-}
-
-func Test_this(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- typeof this;
- `, "object")
- })
-}
-
-func TestWhile(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- limit = 4
- abc = 0
- while (limit) {
- abc = abc + 1
- limit = limit - 1
- }
- abc;
- `, 4)
- })
-}
-
-func TestSwitch_break(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var abc = true;
- var ghi = "Xyzzy";
- while (abc) {
- switch ('def') {
- case 'def':
- break;
- }
- ghi = "Nothing happens.";
- abc = false;
- }
- ghi;
- `, "Nothing happens.")
-
- test(`
- var abc = true;
- var ghi = "Xyzzy";
- WHILE:
- while (abc) {
- switch ('def') {
- case 'def':
- break WHILE;
- }
- ghi = "Nothing happens."
- abc = false
- }
- ghi;
- `, "Xyzzy")
-
- test(`
- var ghi = "Xyzzy";
- FOR:
- for (;;) {
- switch ('def') {
- case 'def':
- break FOR;
- ghi = "";
- }
- ghi = "Nothing happens.";
- }
- ghi;
- `, "Xyzzy")
-
- test(`
- var ghi = "Xyzzy";
- FOR:
- for (var jkl in {}) {
- switch ('def') {
- case 'def':
- break FOR;
- ghi = "Something happens.";
- }
- ghi = "Nothing happens.";
- }
- ghi;
- `, "Xyzzy")
-
- test(`
- var ghi = "Xyzzy";
- function jkl() {
- switch ('def') {
- case 'def':
- break;
- ghi = "";
- }
- ghi = "Nothing happens.";
- }
- while (abc) {
- jkl();
- abc = false;
- ghi = "Something happens.";
- }
- ghi;
- `, "Something happens.")
- })
-}
-
-func TestTryFinally(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var abc;
- try {
- abc = 1;
- }
- finally {
- abc = 2;
- }
- abc;
- `, 2)
-
- test(`
- var abc = false, def = 0;
- do {
- def += 1;
- if (def > 100) {
- break;
- }
- try {
- continue;
- }
- finally {
- abc = true;
- }
- }
- while(!abc && def < 10)
- def;
- `, 1)
-
- test(`
- var abc = false, def = 0, ghi = 0;
- do {
- def += 1;
- if (def > 100) {
- break;
- }
- try {
- throw 0;
- }
- catch (jkl) {
- continue;
- }
- finally {
- abc = true;
- ghi = 11;
- }
- ghi -= 1;
- }
- while(!abc && def < 10)
- ghi;
- `, 11)
-
- test(`
- var abc = 0, def = 0;
- do {
- try {
- abc += 1;
- throw "ghi";
- }
- finally {
- def = 1;
- continue;
- }
- def -= 1;
- }
- while (abc < 2)
- [ abc, def ];
- `, "2,1")
- })
-}
-
-func TestTryCatch(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var abc = 1;
- try {
- throw 4;
- abc = -1;
- }
- catch (xyzzy) {
- abc += xyzzy + 1;
- }
- abc;
- `, 6)
-
- test(`
- abc = 1;
- var def;
- try {
- try {
- throw 4;
- abc = -1;
- }
- catch (xyzzy) {
- abc += xyzzy + 1;
- throw 64;
- }
- }
- catch (xyzzy) {
- def = xyzzy;
- abc = -2;
- }
- [ def, abc ];
- `, "64,-2")
- })
-}
-
-func TestWith(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var def;
- with({ abc: 9 }) {
- def = abc;
- }
- def;
- `, 9)
-
- test(`
- var def;
- with({ abc: function(){
- return 11;
- } }) {
- def = abc();
- }
- def;
- `, 11)
- })
-}
-
-func TestSwitch(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var abc = 0;
- switch (0) {
- default:
- abc += 1;
- case 1:
- abc += 2;
- case 2:
- abc += 4;
- case 3:
- abc += 8;
- }
- abc;
- `, 15)
-
- test(`
- abc = 0;
- switch (3) {
- default:
- abc += 1;
- case 1:
- abc += 2;
- case 2:
- abc += 4;
- case 3:
- abc += 8;
- }
- abc;
- `, 8)
-
- test(`
- abc = 0;
- switch (60) {
- case 1:
- abc += 2;
- case 2:
- abc += 4;
- case 3:
- abc += 8;
- }
- abc;
- `, 0)
- })
-}
-
-func TestForIn(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var abc;
- for (property in { a: 1 }) {
- abc = property;
- }
- abc;
- `, "a")
-
- test(`
- var ghi;
- for (property in new String("xyzzy")) {
- ghi = property;
- }
- ghi;
- `, "4")
- })
-}
-
-func TestFor(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var abc = 7;
- for (i = 0; i < 3; i += 1) {
- abc += 1;
- }
- abc;
- `, 10)
-
- test(`
- abc = 7;
- for (i = 0; i < 3; i += 1) {
- abc += 1;
- if (i == 1) {
- break;
- }
- }
- abc;
- `, 9)
-
- test(`
- abc = 7;
- for (i = 0; i < 3; i += 1) {
- if (i == 2) {
- continue;
- }
- abc += 1;
- }
- abc;
- `, 9)
-
- test(`
- abc = 0;
- for (;;) {
- abc += 1;
- if (abc == 3)
- break;
- }
- abc;
- `, 3)
-
- test(`
- for (abc = 0; ;) {
- abc += 1;
- if (abc == 3)
- break;
- }
- abc;
- `, 3)
-
- test(`
- for (abc = 0; ; abc += 1) {
- abc += 1;
- if (abc == 3)
- break;
- }
- abc;
- `, 3)
- })
-}
-
-func TestLabelled(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- // TODO Add emergency break
-
- test(`
- xyzzy: for (var abc = 0; abc <= 0; abc++) {
- for (var def = 0; def <= 1; def++) {
- if (def === 0) {
- continue xyzzy;
- } else {
- }
- }
- }
- `)
-
- test(`
- abc = 0
- def:
- while (true) {
- while (true) {
- abc = abc + 1
- if (abc > 11) {
- break def;
- }
- }
- }
- abc;
- `, 12)
-
- test(`
- abc = 0
- def:
- do {
- do {
- abc = abc + 1
- if (abc > 11) {
- break def;
- }
- } while (true)
- } while (true)
- abc;
- `, 12)
- })
-}
-
-func TestConditional(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- [ true ? false : true, true ? 1 : 0, false ? 3.14159 : "abc" ];
- `, "false,1,abc")
- })
-}
-
-func TestArrayLiteral(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- [ 1, , 3.14159 ];
- `, "1,,3.14159")
- })
-}
-
-func TestAssignment(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var abc = 1;
- abc;
- `, 1)
-
- test(`
- abc += 2;
- abc;
- `, 3)
- })
-}
-
-func TestBinaryOperation(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`0 == 1`, false)
- test(`1 == "1"`, true)
- test(`0 === 1`, false)
- test(`1 === "1"`, false)
- test(`"1" === "1"`, true)
- })
-}
-
-func Test_typeof(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`typeof abc`, "undefined")
- test(`typeof abc === 'undefined'`, true)
- test(`typeof {}`, "object")
- test(`typeof null`, "object")
- })
-}
-
-func Test_PrimitiveValueObjectValue(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- Number11 := test(`new Number(11)`)
- is(Number11.float64(), 11)
- })
-}
-
-func Test_eval(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- // FIXME terst, Is this correct?
- test(`
- var abc = 1;
- `, "undefined")
-
- test(`
- eval("abc += 1");
- `, 2)
-
- test(`
- (function(){
- var abc = 11;
- eval("abc += 1");
- return abc;
- })();
- `, 12)
- test(`abc`, 2)
-
- test(`
- (function(){
- try {
- eval("var prop = \\u2029;");
- return false;
- } catch (abc) {
- return [ abc instanceof SyntaxError, abc.toString() ];
- }
- })();
- `, "true,SyntaxError: Unexpected token ILLEGAL")
-
- test(`
- function abc(){
- this.THIS = eval("this");
- }
- var def = new abc();
- def === def.THIS;
- `, true)
- })
-}
-
-func Test_evalDirectIndirect(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- // (function () {return this;}()).abc = "global";
- test(`
- var abc = "global";
- (function(){
- try {
- var _eval = eval;
- var abc = "function";
- return [
- _eval("\'global\' === abc"), // eval (Indirect)
- eval("\'function\' === abc"), // eval (Direct)
- ];
- } finally {
- delete this.abc;
- }
- })();
- `, "true,true")
- })
-}
-
-func TestError_URIError(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`new URIError() instanceof URIError`, true)
-
- test(`
- var abc
- try {
- decodeURI("http://example.com/ _^#%")
- }
- catch (def) {
- abc = def instanceof URIError
- }
- abc
- `, true)
- })
-}
-
-func TestTo(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- {
- value, _ := test(`"11"`).ToFloat()
- is(value, float64(11))
- }
-
- {
- value, _ := test(`"11"`).ToInteger()
- is(value, int64(11))
-
- value, _ = test(`1.1`).ToInteger()
- is(value, int64(1))
- }
- })
-}
-
-func TestShouldError(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`raise:
- xyzzy
- throw new TypeError("Nothing happens.")
- `, "ReferenceError: 'xyzzy' is not defined")
- })
-}
-
-func TestAPI(t *testing.T) {
- tt(t, func() {
- test, vm := test()
-
- test(`
- String.prototype.xyzzy = function(){
- return this.length + 11 + (arguments[0] || 0)
- }
- abc = new String("xyzzy")
- def = "Nothing happens."
- abc.xyzzy()
- `, 16)
- abc, _ := vm.Get("abc")
- def, _ := vm.Get("def")
- object := abc.Object()
- result, _ := object.Call("xyzzy")
- is(result, 16)
- result, _ = object.Call("xyzzy", 1)
- is(result, 17)
- value, _ := object.Get("xyzzy")
- result, _ = value.Call(def)
- is(result, 27)
- result, _ = value.Call(def, 3)
- is(result, 30)
- object = value.Object() // Object xyzzy
- result, _ = object.Value().Call(def, 3)
- is(result, 30)
-
- test(`
- abc = {
- 'abc': 1,
- 'def': false,
- 3.14159: NaN,
- };
- abc['abc'];
- `, 1)
- abc, err := vm.Get("abc")
- is(err, nil)
- object = abc.Object() // Object abc
- value, err = object.Get("abc")
- is(err, nil)
- is(value, 1)
- is(object.Keys(), []string{"abc", "def", "3.14159"})
-
- test(`
- abc = [ 0, 1, 2, 3.14159, "abc", , ];
- abc.def = true;
- `)
- abc, err = vm.Get("abc")
- is(err, nil)
- object = abc.Object() // Object abc
- is(object.Keys(), []string{"0", "1", "2", "3", "4", "def"})
- })
-}
-
-func TestUnicode(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`var abc = eval("\"a\uFFFFa\"");`, "undefined")
-
- test(`abc.length`, 3)
-
- test(`abc != "aa"`, true)
-
- test("abc[1] === \"\uFFFF\"", true)
- })
-}
-
-func TestDotMember(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- abc = {
- ghi: 11,
- }
- abc.def = "Xyzzy"
- abc.null = "Nothing happens."
- `)
- test(`abc.def`, "Xyzzy")
- test(`abc.null`, "Nothing happens.")
- test(`abc.ghi`, 11)
-
- test(`
- abc = {
- null: 11,
- }
- `)
- test(`abc.def`, "undefined")
- test(`abc.null`, 11)
- test(`abc.ghi`, "undefined")
- })
-}
-
-func Test_stringToFloat(t *testing.T) {
- tt(t, func() {
-
- is(parseNumber("10e10000"), _Infinity)
- is(parseNumber("10e10_."), _NaN)
- })
-}
-
-func Test_delete(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- delete 42;
- `, true)
-
- test(`
- var abc = delete $_undefined_$;
- abc = abc && delete ($_undefined_$);
- abc;
- `, true)
-
- // delete should not trigger get()
- test(`
- var abc = {
- get def() {
- throw "Test_delete: delete should not trigger get()"
- }
- };
- delete abc.def
- `, true)
- })
-}
-
-func TestObject_defineOwnProperty(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var object = {};
-
- var descriptor = new Boolean(false);
- descriptor.configurable = true;
-
- Object.defineProperties(object, {
- property: descriptor
- });
-
- var abc = object.hasOwnProperty("property");
- delete object.property;
- var def = object.hasOwnProperty("property");
-
- [ abc, def ];
- `, "true,false")
-
- test(`
- var object = [0, 1, 2];
- Object.defineProperty(object, "0", {
- value: 42,
- writable: false,
- enumerable: false,
- configurable: false
- });
- var abc = Object.getOwnPropertyDescriptor(object, "0");
- [ abc.value, abc.writable, abc.enumerable, abc.configurable ];
- `, "42,false,false,false")
-
- test(`
- var abc = { "xyzzy": 42 };
- var def = Object.defineProperties(abc, "");
- abc === def;
- `, true)
- })
-}
-
-func Test_assignmentEvaluationOrder(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var abc = 0;
- ((abc = 1) & abc);
- `, 1)
-
- test(`
- var abc = 0;
- (abc & (abc = 1));
- `, 0)
- })
-}
-
-func TestOttoCall(t *testing.T) {
- tt(t, func() {
- vm := New()
-
- _, err := vm.Run(`
- var abc = {
- ghi: 1,
- def: function(def){
- var ghi = 0;
- if (this.ghi) {
- ghi = this.ghi;
- }
- return "def: " + (def + 3.14159 + ghi);
- }
- };
- `)
- is(err, nil)
-
- value, err := vm.Call(`abc.def`, nil, 2)
- is(err, nil)
- is(value, "def: 6.14159")
-
- value, err = vm.Call(`abc.def`, "", 2)
- is(err, nil)
- is(value, "def: 5.14159")
-
- // Do not attempt to do a ToValue on a this of nil
- value, err = vm.Call(`jkl.def`, nil, 1, 2, 3)
- is(err, "!=", nil)
- is(value, "undefined")
-
- value, err = vm.Call(`[ 1, 2, 3, undefined, 4 ].concat`, nil, 5, 6, 7, "abc")
- is(err, nil)
- is(value, "1,2,3,,4,5,6,7,abc")
- })
-}
-
-func TestOttoCall_new(t *testing.T) {
- tt(t, func() {
- test, vm := test()
-
- vm.Set("abc", func(call FunctionCall) Value {
- value, err := call.Otto.Call(`new Object`, nil, "Nothing happens.")
- is(err, nil)
- return value
- })
- test(`
- def = abc();
- [ def, def instanceof String ];
- `, "Nothing happens.,true")
- })
-}
-
-func TestOttoCall_throw(t *testing.T) {
- // FIXME? (Been broken for a while)
- // Looks like this has been broken for a while... what
- // behavior do we want here?
-
- if true {
- return
- }
-
- tt(t, func() {
- test, vm := test()
-
- vm.Set("abc", func(call FunctionCall) Value {
- if false {
- call.Otto.Call(`throw eval`, nil, "({ def: 3.14159 })")
- }
- call.Otto.Call(`throw Error`, nil, "abcdef")
- return Value{}
- })
- // TODO try { abc(); } catch (err) { error = err }
- // Possible unrelated error case:
- // If error is not declared beforehand, is later referencing it a ReferenceError?
- // Should the catch { } declare error in the outer scope?
- test(`
- var error;
- try {
- abc();
- }
- catch (err) {
- error = err;
- }
- [ error instanceof Error, error.message, error.def ];
- `, "true,abcdef,")
-
- vm.Set("def", func(call FunctionCall) Value {
- call.Otto.Call(`throw new Object`, nil, 3.14159)
- return UndefinedValue()
- })
- test(`
- try {
- def();
- }
- catch (err) {
- error = err;
- }
- [ error instanceof Error, error.message, error.def, typeof error, error, error instanceof Number ];
- `, "false,,,object,3.14159,true")
- })
-}
-
-func TestOttoCopy(t *testing.T) {
- tt(t, func() {
- vm0 := New()
- vm0.Run(`
- var abc = function() {
- return "Xyzzy";
- };
-
- function def() {
- return abc() + (0 + {});
- }
- `)
-
- value, err := vm0.Run(`
- def();
- `)
- is(err, nil)
- is(value, "Xyzzy0[object Object]")
-
- vm1 := vm0.Copy()
- value, err = vm1.Run(`
- def();
- `)
- is(err, nil)
- is(value, "Xyzzy0[object Object]")
-
- vm1.Run(`
- abc = function() {
- return 3.14159;
- };
- `)
- value, err = vm1.Run(`
- def();
- `)
- is(err, nil)
- is(value, "3.141590[object Object]")
-
- value, err = vm0.Run(`
- def();
- `)
- is(err, nil)
- is(value, "Xyzzy0[object Object]")
-
- {
- vm0 := New()
- vm0.Run(`
- var global = (function () {return this;}())
- var abc = 0;
- var vm = "vm0";
-
- var def = (function(){
- var jkl = 0;
- var abc = function() {
- global.abc += 1;
- jkl += 1;
- return 1;
- };
-
- return function() {
- return [ vm, global.abc, jkl, abc() ];
- };
- })();
- `)
-
- value, err := vm0.Run(`
- def();
- `)
- is(err, nil)
- is(value, "vm0,0,0,1")
-
- vm1 := vm0.Copy()
- vm1.Set("vm", "vm1")
- value, err = vm1.Run(`
- def();
- `)
- is(err, nil)
- is(value, "vm1,1,1,1")
-
- value, err = vm0.Run(`
- def();
- `)
- is(err, nil)
- is(value, "vm0,1,1,1")
-
- value, err = vm1.Run(`
- def();
- `)
- is(err, nil)
- is(value, "vm1,2,2,1")
- }
- })
-}
-
-func TestOttoCall_clone(t *testing.T) {
- tt(t, func() {
- vm := New().clone()
- rt := vm.runtime
-
- {
- // FIXME terst, Check how this comparison is done
- is(rt.global.Array.prototype, rt.global.FunctionPrototype)
- is(rt.global.ArrayPrototype, "!=", nil)
- is(rt.global.Array.runtime, rt)
- is(rt.global.Array.prototype.runtime, rt)
- is(rt.global.Array.get("prototype")._object().runtime, rt)
- }
-
- {
- value, err := vm.Run(`[ 1, 2, 3 ].toString()`)
- is(err, nil)
- is(value, "1,2,3")
- }
-
- {
- value, err := vm.Run(`[ 1, 2, 3 ]`)
- is(err, nil)
- is(value, "1,2,3")
- object := value._object()
- is(object, "!=", nil)
- is(object.prototype, rt.global.ArrayPrototype)
-
- value, err = vm.Run(`Array.prototype`)
- is(err, nil)
- object = value._object()
- is(object.runtime, rt)
- is(object, "!=", nil)
- is(object, rt.global.ArrayPrototype)
- }
-
- {
- otto1 := New()
- _, err := otto1.Run(`
- var abc = 1;
- var def = 2;
- `)
- is(err, nil)
-
- otto2 := otto1.clone()
- value, err := otto2.Run(`abc += 1; abc;`)
- is(err, nil)
- is(value, 2)
-
- value, err = otto1.Run(`abc += 4; abc;`)
- is(err, nil)
- is(value, 5)
- }
-
- {
- vm1 := New()
- _, err := vm1.Run(`
- var abc = 1;
- var def = function(value) {
- abc += value;
- return abc;
- }
- `)
- is(err, nil)
-
- vm2 := vm1.clone()
- value, err := vm2.Run(`def(1)`)
- is(err, nil)
- is(value, 2)
-
- value, err = vm1.Run(`def(4)`)
- is(err, nil)
- is(value, 5)
- }
-
- {
- vm1 := New()
- _, err := vm1.Run(`
- var abc = {
- ghi: 1,
- jkl: function(value) {
- this.ghi += value;
- return this.ghi;
- }
- };
- var def = {
- abc: abc
- };
- `)
- is(err, nil)
-
- otto2 := vm1.clone()
- value, err := otto2.Run(`def.abc.jkl(1)`)
- is(err, nil)
- is(value, 2)
-
- value, err = vm1.Run(`def.abc.jkl(4)`)
- is(err, nil)
- is(value, 5)
- }
-
- {
- vm1 := New()
- _, err := vm1.Run(`
- var abc = function() { return "abc"; };
- var def = function() { return "def"; };
- `)
- is(err, nil)
-
- vm2 := vm1.clone()
- value, err := vm2.Run(`
- [ abc.toString(), def.toString() ];
- `)
- is(value, `function() { return "abc"; },function() { return "def"; }`)
-
- _, err = vm2.Run(`
- var def = function() { return "ghi"; };
- `)
- is(err, nil)
-
- value, err = vm1.Run(`
- [ abc.toString(), def.toString() ];
- `)
- is(value, `function() { return "abc"; },function() { return "def"; }`)
-
- value, err = vm2.Run(`
- [ abc.toString(), def.toString() ];
- `)
- is(value, `function() { return "abc"; },function() { return "ghi"; }`)
- }
-
- })
-}
-
-func TestOttoRun(t *testing.T) {
- tt(t, func() {
- vm := New()
-
- program, err := parser.ParseFile(nil, "", "", 0)
- is(err, nil)
- value, err := vm.Run(program)
- is(err, nil)
- is(value, UndefinedValue())
-
- program, err = parser.ParseFile(nil, "", "2 + 2", 0)
- is(err, nil)
- value, err = vm.Run(program)
- is(err, nil)
- is(value, 4)
- value, err = vm.Run(program)
- is(err, nil)
- is(value, 4)
-
- program, err = parser.ParseFile(nil, "", "var abc; if (!abc) abc = 0; abc += 2; abc;", 0)
- value, err = vm.Run(program)
- is(err, nil)
- is(value, 2)
- value, err = vm.Run(program)
- is(err, nil)
- is(value, 4)
- value, err = vm.Run(program)
- is(err, nil)
- is(value, 6)
-
- {
- src := []byte("var abc; if (!abc) abc = 0; abc += 2; abc;")
- value, err = vm.Run(src)
- is(err, nil)
- is(value, 8)
-
- value, err = vm.Run(bytes.NewBuffer(src))
- is(err, nil)
- is(value, 10)
-
- value, err = vm.Run(io.Reader(bytes.NewBuffer(src)))
- is(err, nil)
- is(value, 12)
- }
-
- {
- script, err := vm.Compile("", `var abc; if (!abc) abc = 0; abc += 2; abc;`)
- is(err, nil)
-
- value, err = vm.Run(script)
- is(err, nil)
- is(value, 14)
-
- value, err = vm.Run(script)
- is(err, nil)
- is(value, 16)
-
- is(script.String(), "// \nvar abc; if (!abc) abc = 0; abc += 2; abc;")
- }
- })
-}
-
-func Test_objectLength(t *testing.T) {
- tt(t, func() {
- _, vm := test()
-
- value := vm.Set("abc", []string{"jkl", "mno"})
- is(objectLength(value._object()), 2)
-
- value, _ = vm.Run(`[1, 2, 3]`)
- is(objectLength(value._object()), 3)
-
- value, _ = vm.Run(`new String("abcdefghi")`)
- is(objectLength(value._object()), 9)
-
- value, _ = vm.Run(`"abcdefghi"`)
- is(objectLength(value._object()), 0)
- })
-}
-
-func BenchmarkNew(b *testing.B) {
- for i := 0; i < b.N; i++ {
- New()
- }
-}
-
-func BenchmarkClone(b *testing.B) {
- vm := New()
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- vm.clone()
- }
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/panic_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/panic_test.go
deleted file mode 100644
index 06f0a64fc..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/panic_test.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package otto
-
-import (
- "testing"
-)
-
-func Test_panic(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- // Test that property.value is set to something if writable is set
- // to something
- test(`
- var abc = [];
- Object.defineProperty(abc, "0", { writable: false });
- Object.defineProperty(abc, "0", { writable: false });
- "0" in abc;
- `, true)
-
- test(`raise:
- var abc = [];
- Object.defineProperty(abc, "0", { writable: false });
- Object.defineProperty(abc, "0", { value: false, writable: false });
- `, "TypeError")
-
- // Test that a regular expression can contain \c0410 (CYRILLIC CAPITAL LETTER A)
- // without panicking
- test(`
- var abc = 0x0410;
- var def = String.fromCharCode(abc);
- new RegExp("\\c" + def).exec(def);
- `, "null")
-
- // Test transforming a transformable regular expression without a panic
- test(`
- new RegExp("\\u0000");
- new RegExp("\\undefined").test("undefined");
- `, true)
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/expression.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/expression.go
index dc397b5cb..8baf22f7c 100644
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/expression.go
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/expression.go
@@ -417,7 +417,7 @@ func (self *_parser) parseLeftHandSideExpression() ast.Expression {
for {
if self.token == token.PERIOD {
left = self.parseDotMember(left)
- } else if self.token == token.LEFT_BRACE {
+ } else if self.token == token.LEFT_BRACKET {
left = self.parseBracketMember(left)
} else {
break
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/lexer_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/lexer_test.go
deleted file mode 100644
index 37eb7a464..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/lexer_test.go
+++ /dev/null
@@ -1,380 +0,0 @@
-package parser
-
-import (
- "../terst"
- "testing"
-
- "github.com/robertkrimen/otto/file"
- "github.com/robertkrimen/otto/token"
-)
-
-var tt = terst.Terst
-var is = terst.Is
-
-func TestLexer(t *testing.T) {
- tt(t, func() {
- setup := func(src string) *_parser {
- parser := newParser("", src)
- return parser
- }
-
- test := func(src string, test ...interface{}) {
- parser := setup(src)
- for len(test) > 0 {
- tkn, literal, idx := parser.scan()
- if len(test) > 0 {
- is(tkn, test[0].(token.Token))
- test = test[1:]
- }
- if len(test) > 0 {
- is(literal, test[0].(string))
- test = test[1:]
- }
- if len(test) > 0 {
- // FIXME terst, Fix this so that cast to file.Idx is not necessary?
- is(idx, file.Idx(test[0].(int)))
- test = test[1:]
- }
- }
- }
-
- test("",
- token.EOF, "", 1,
- )
-
- test("1",
- token.NUMBER, "1", 1,
- token.EOF, "", 2,
- )
-
- test(".0",
- token.NUMBER, ".0", 1,
- token.EOF, "", 3,
- )
-
- test("abc",
- token.IDENTIFIER, "abc", 1,
- token.EOF, "", 4,
- )
-
- test("abc(1)",
- token.IDENTIFIER, "abc", 1,
- token.LEFT_PARENTHESIS, "", 4,
- token.NUMBER, "1", 5,
- token.RIGHT_PARENTHESIS, "", 6,
- token.EOF, "", 7,
- )
-
- test(".",
- token.PERIOD, "", 1,
- token.EOF, "", 2,
- )
-
- test("===.",
- token.STRICT_EQUAL, "", 1,
- token.PERIOD, "", 4,
- token.EOF, "", 5,
- )
-
- test(">>>=.0",
- token.UNSIGNED_SHIFT_RIGHT_ASSIGN, "", 1,
- token.NUMBER, ".0", 5,
- token.EOF, "", 7,
- )
-
- test(">>>=0.0.",
- token.UNSIGNED_SHIFT_RIGHT_ASSIGN, "", 1,
- token.NUMBER, "0.0", 5,
- token.PERIOD, "", 8,
- token.EOF, "", 9,
- )
-
- test("\"abc\"",
- token.STRING, "\"abc\"", 1,
- token.EOF, "", 6,
- )
-
- test("abc = //",
- token.IDENTIFIER, "abc", 1,
- token.ASSIGN, "", 5,
- token.EOF, "", 9,
- )
-
- test("abc = 1 / 2",
- token.IDENTIFIER, "abc", 1,
- token.ASSIGN, "", 5,
- token.NUMBER, "1", 7,
- token.SLASH, "", 9,
- token.NUMBER, "2", 11,
- token.EOF, "", 12,
- )
-
- test("xyzzy = 'Nothing happens.'",
- token.IDENTIFIER, "xyzzy", 1,
- token.ASSIGN, "", 7,
- token.STRING, "'Nothing happens.'", 9,
- token.EOF, "", 27,
- )
-
- test("abc = !false",
- token.IDENTIFIER, "abc", 1,
- token.ASSIGN, "", 5,
- token.NOT, "", 7,
- token.BOOLEAN, "false", 8,
- token.EOF, "", 13,
- )
-
- test("abc = !!true",
- token.IDENTIFIER, "abc", 1,
- token.ASSIGN, "", 5,
- token.NOT, "", 7,
- token.NOT, "", 8,
- token.BOOLEAN, "true", 9,
- token.EOF, "", 13,
- )
-
- test("abc *= 1",
- token.IDENTIFIER, "abc", 1,
- token.MULTIPLY_ASSIGN, "", 5,
- token.NUMBER, "1", 8,
- token.EOF, "", 9,
- )
-
- test("if 1 else",
- token.IF, "if", 1,
- token.NUMBER, "1", 4,
- token.ELSE, "else", 6,
- token.EOF, "", 10,
- )
-
- test("null",
- token.NULL, "null", 1,
- token.EOF, "", 5,
- )
-
- test(`"\u007a\x79\u000a\x78"`,
- token.STRING, "\"\\u007a\\x79\\u000a\\x78\"", 1,
- token.EOF, "", 23,
- )
-
- test(`"[First line \
-Second line \
- Third line\
-. ]"
- `,
- token.STRING, "\"[First line \\\nSecond line \\\n Third line\\\n. ]\"", 1,
- token.EOF, "", 53,
- )
-
- test("/",
- token.SLASH, "", 1,
- token.EOF, "", 2,
- )
-
- test("var abc = \"abc\uFFFFabc\"",
- token.VAR, "var", 1,
- token.IDENTIFIER, "abc", 5,
- token.ASSIGN, "", 9,
- token.STRING, "\"abc\uFFFFabc\"", 11,
- token.EOF, "", 22,
- )
-
- test(`'\t' === '\r'`,
- token.STRING, "'\\t'", 1,
- token.STRICT_EQUAL, "", 6,
- token.STRING, "'\\r'", 10,
- token.EOF, "", 14,
- )
-
- test(`var \u0024 = 1`,
- token.VAR, "var", 1,
- token.IDENTIFIER, "$", 5,
- token.ASSIGN, "", 12,
- token.NUMBER, "1", 14,
- token.EOF, "", 15,
- )
-
- test("10e10000",
- token.NUMBER, "10e10000", 1,
- token.EOF, "", 9,
- )
-
- test(`var if var class`,
- token.VAR, "var", 1,
- token.IF, "if", 5,
- token.VAR, "var", 8,
- token.KEYWORD, "class", 12,
- token.EOF, "", 17,
- )
-
- test(`-0`,
- token.MINUS, "", 1,
- token.NUMBER, "0", 2,
- token.EOF, "", 3,
- )
-
- test(`.01`,
- token.NUMBER, ".01", 1,
- token.EOF, "", 4,
- )
-
- test(`.01e+2`,
- token.NUMBER, ".01e+2", 1,
- token.EOF, "", 7,
- )
-
- test(";",
- token.SEMICOLON, "", 1,
- token.EOF, "", 2,
- )
-
- test(";;",
- token.SEMICOLON, "", 1,
- token.SEMICOLON, "", 2,
- token.EOF, "", 3,
- )
-
- test("//",
- token.EOF, "", 3,
- )
-
- test(";;//",
- token.SEMICOLON, "", 1,
- token.SEMICOLON, "", 2,
- token.EOF, "", 5,
- )
-
- test("1",
- token.NUMBER, "1", 1,
- )
-
- test("12 123",
- token.NUMBER, "12", 1,
- token.NUMBER, "123", 4,
- )
-
- test("1.2 12.3",
- token.NUMBER, "1.2", 1,
- token.NUMBER, "12.3", 5,
- )
-
- test("/ /=",
- token.SLASH, "", 1,
- token.QUOTIENT_ASSIGN, "", 3,
- )
-
- test(`"abc"`,
- token.STRING, `"abc"`, 1,
- )
-
- test(`'abc'`,
- token.STRING, `'abc'`, 1,
- )
-
- test("++",
- token.INCREMENT, "", 1,
- )
-
- test(">",
- token.GREATER, "", 1,
- )
-
- test(">=",
- token.GREATER_OR_EQUAL, "", 1,
- )
-
- test(">>",
- token.SHIFT_RIGHT, "", 1,
- )
-
- test(">>=",
- token.SHIFT_RIGHT_ASSIGN, "", 1,
- )
-
- test(">>>",
- token.UNSIGNED_SHIFT_RIGHT, "", 1,
- )
-
- test(">>>=",
- token.UNSIGNED_SHIFT_RIGHT_ASSIGN, "", 1,
- )
-
- test("1 \"abc\"",
- token.NUMBER, "1", 1,
- token.STRING, "\"abc\"", 3,
- )
-
- test(",",
- token.COMMA, "", 1,
- )
-
- test("1, \"abc\"",
- token.NUMBER, "1", 1,
- token.COMMA, "", 2,
- token.STRING, "\"abc\"", 4,
- )
-
- test("new abc(1, 3.14159);",
- token.NEW, "new", 1,
- token.IDENTIFIER, "abc", 5,
- token.LEFT_PARENTHESIS, "", 8,
- token.NUMBER, "1", 9,
- token.COMMA, "", 10,
- token.NUMBER, "3.14159", 12,
- token.RIGHT_PARENTHESIS, "", 19,
- token.SEMICOLON, "", 20,
- )
-
- test("1 == \"1\"",
- token.NUMBER, "1", 1,
- token.EQUAL, "", 3,
- token.STRING, "\"1\"", 6,
- )
-
- test("1\n[]\n",
- token.NUMBER, "1", 1,
- token.LEFT_BRACKET, "", 3,
- token.RIGHT_BRACKET, "", 4,
- )
-
- test("1\ufeff[]\ufeff",
- token.NUMBER, "1", 1,
- token.LEFT_BRACKET, "", 5,
- token.RIGHT_BRACKET, "", 6,
- )
-
- // ILLEGAL
-
- test(`3ea`,
- token.ILLEGAL, "3e", 1,
- token.IDENTIFIER, "a", 3,
- token.EOF, "", 4,
- )
-
- test(`3in`,
- token.ILLEGAL, "3", 1,
- token.IN, "in", 2,
- token.EOF, "", 4,
- )
-
- test("\"Hello\nWorld\"",
- token.ILLEGAL, "", 1,
- token.IDENTIFIER, "World", 8,
- token.ILLEGAL, "", 13,
- token.EOF, "", 14,
- )
-
- test("\u203f = 10",
- token.ILLEGAL, "", 1,
- token.ASSIGN, "", 5,
- token.NUMBER, "10", 7,
- token.EOF, "", 9,
- )
-
- test(`"\x0G"`,
- token.STRING, "\"\\x0G\"", 1,
- token.EOF, "", 7,
- )
-
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/marshal_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/marshal_test.go
deleted file mode 100644
index f54cd2d4f..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/marshal_test.go
+++ /dev/null
@@ -1,930 +0,0 @@
-package parser
-
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "os"
- "reflect"
- "strings"
- "testing"
-
- "github.com/robertkrimen/otto/ast"
-)
-
-func marshal(name string, children ...interface{}) interface{} {
- if len(children) == 1 {
- if name == "" {
- return testMarshalNode(children[0])
- }
- return map[string]interface{}{
- name: children[0],
- }
- }
- map_ := map[string]interface{}{}
- length := len(children) / 2
- for i := 0; i < length; i++ {
- name := children[i*2].(string)
- value := children[i*2+1]
- map_[name] = value
- }
- if name == "" {
- return map_
- }
- return map[string]interface{}{
- name: map_,
- }
-}
-
-func testMarshalNode(node interface{}) interface{} {
- switch node := node.(type) {
-
- // Expression
-
- case *ast.ArrayLiteral:
- return marshal("Array", testMarshalNode(node.Value))
-
- case *ast.AssignExpression:
- return marshal("Assign",
- "Left", testMarshalNode(node.Left),
- "Right", testMarshalNode(node.Right),
- )
-
- case *ast.BinaryExpression:
- return marshal("BinaryExpression",
- "Operator", node.Operator.String(),
- "Left", testMarshalNode(node.Left),
- "Right", testMarshalNode(node.Right),
- )
-
- case *ast.BooleanLiteral:
- return marshal("Literal", node.Value)
-
- case *ast.CallExpression:
- return marshal("Call",
- "Callee", testMarshalNode(node.Callee),
- "ArgumentList", testMarshalNode(node.ArgumentList),
- )
-
- case *ast.ConditionalExpression:
- return marshal("Conditional",
- "Test", testMarshalNode(node.Test),
- "Consequent", testMarshalNode(node.Consequent),
- "Alternate", testMarshalNode(node.Alternate),
- )
-
- case *ast.DotExpression:
- return marshal("Dot",
- "Left", testMarshalNode(node.Left),
- "Member", node.Identifier.Name,
- )
-
- case *ast.NewExpression:
- return marshal("New",
- "Callee", testMarshalNode(node.Callee),
- "ArgumentList", testMarshalNode(node.ArgumentList),
- )
-
- case *ast.NullLiteral:
- return marshal("Literal", nil)
-
- case *ast.NumberLiteral:
- return marshal("Literal", node.Value)
-
- case *ast.ObjectLiteral:
- return marshal("Object", testMarshalNode(node.Value))
-
- case *ast.RegExpLiteral:
- return marshal("Literal", node.Literal)
-
- case *ast.StringLiteral:
- return marshal("Literal", node.Literal)
-
- case *ast.VariableExpression:
- return []interface{}{node.Name, testMarshalNode(node.Initializer)}
-
- // Statement
-
- case *ast.Program:
- return testMarshalNode(node.Body)
-
- case *ast.BlockStatement:
- return marshal("BlockStatement", testMarshalNode(node.List))
-
- case *ast.EmptyStatement:
- return "EmptyStatement"
-
- case *ast.ExpressionStatement:
- return testMarshalNode(node.Expression)
-
- case *ast.ForInStatement:
- return marshal("ForIn",
- "Into", marshal("", node.Into),
- "Source", marshal("", node.Source),
- "Body", marshal("", node.Body),
- )
-
- case *ast.FunctionLiteral:
- return marshal("Function", testMarshalNode(node.Body))
-
- case *ast.Identifier:
- return marshal("Identifier", node.Name)
-
- case *ast.IfStatement:
- if_ := marshal("",
- "Test", testMarshalNode(node.Test),
- "Consequent", testMarshalNode(node.Consequent),
- ).(map[string]interface{})
- if node.Alternate != nil {
- if_["Alternate"] = testMarshalNode(node.Alternate)
- }
- return marshal("If", if_)
-
- case *ast.LabelledStatement:
- return marshal("Label",
- "Name", node.Label.Name,
- "Statement", testMarshalNode(node.Statement),
- )
- case ast.Property:
- return marshal("",
- "Key", node.Key,
- "Value", testMarshalNode(node.Value),
- )
-
- case *ast.ReturnStatement:
- return marshal("Return", testMarshalNode(node.Argument))
-
- case *ast.SequenceExpression:
- return marshal("Sequence", testMarshalNode(node.Sequence))
-
- case *ast.ThrowStatement:
- return marshal("Throw", testMarshalNode(node.Argument))
-
- case *ast.VariableStatement:
- return marshal("Var", testMarshalNode(node.List))
-
- }
-
- {
- value := reflect.ValueOf(node)
- if value.Kind() == reflect.Slice {
- tmp0 := []interface{}{}
- for index := 0; index < value.Len(); index++ {
- tmp0 = append(tmp0, testMarshalNode(value.Index(index).Interface()))
- }
- return tmp0
- }
- }
-
- if node != nil {
- fmt.Fprintf(os.Stderr, "testMarshalNode(%T)\n", node)
- }
-
- return nil
-}
-
-func testMarshal(node interface{}) string {
- value, err := json.Marshal(testMarshalNode(node))
- if err != nil {
- panic(err)
- }
- return string(value)
-}
-
-func TestParserAST(t *testing.T) {
- tt(t, func() {
-
- test := func(inputOutput string) {
- match := matchBeforeAfterSeparator.FindStringIndex(inputOutput)
- input := strings.TrimSpace(inputOutput[0:match[0]])
- wantOutput := strings.TrimSpace(inputOutput[match[1]:])
- _, program, err := testParse(input)
- is(err, nil)
- haveOutput := testMarshal(program)
- tmp0, tmp1 := bytes.Buffer{}, bytes.Buffer{}
- json.Indent(&tmp0, []byte(haveOutput), "\t\t", " ")
- json.Indent(&tmp1, []byte(wantOutput), "\t\t", " ")
- is("\n\t\t"+tmp0.String(), "\n\t\t"+tmp1.String())
- }
-
- test(`
- ---
-[]
- `)
-
- test(`
- ;
- ---
-[
- "EmptyStatement"
-]
- `)
-
- test(`
- ;;;
- ---
-[
- "EmptyStatement",
- "EmptyStatement",
- "EmptyStatement"
-]
- `)
-
- test(`
- 1; true; abc; "abc"; null;
- ---
-[
- {
- "Literal": 1
- },
- {
- "Literal": true
- },
- {
- "Identifier": "abc"
- },
- {
- "Literal": "\"abc\""
- },
- {
- "Literal": null
- }
-]
- `)
-
- test(`
- { 1; null; 3.14159; ; }
- ---
-[
- {
- "BlockStatement": [
- {
- "Literal": 1
- },
- {
- "Literal": null
- },
- {
- "Literal": 3.14159
- },
- "EmptyStatement"
- ]
- }
-]
- `)
-
- test(`
- new abc();
- ---
-[
- {
- "New": {
- "ArgumentList": [],
- "Callee": {
- "Identifier": "abc"
- }
- }
- }
-]
- `)
-
- test(`
- new abc(1, 3.14159)
- ---
-[
- {
- "New": {
- "ArgumentList": [
- {
- "Literal": 1
- },
- {
- "Literal": 3.14159
- }
- ],
- "Callee": {
- "Identifier": "abc"
- }
- }
- }
-]
- `)
-
- test(`
- true ? false : true
- ---
-[
- {
- "Conditional": {
- "Alternate": {
- "Literal": true
- },
- "Consequent": {
- "Literal": false
- },
- "Test": {
- "Literal": true
- }
- }
- }
-]
- `)
-
- test(`
- true || false
- ---
-[
- {
- "BinaryExpression": {
- "Left": {
- "Literal": true
- },
- "Operator": "||",
- "Right": {
- "Literal": false
- }
- }
- }
-]
- `)
-
- test(`
- 0 + { abc: true }
- ---
-[
- {
- "BinaryExpression": {
- "Left": {
- "Literal": 0
- },
- "Operator": "+",
- "Right": {
- "Object": [
- {
- "Key": "abc",
- "Value": {
- "Literal": true
- }
- }
- ]
- }
- }
- }
-]
- `)
-
- test(`
- 1 == "1"
- ---
-[
- {
- "BinaryExpression": {
- "Left": {
- "Literal": 1
- },
- "Operator": "==",
- "Right": {
- "Literal": "\"1\""
- }
- }
- }
-]
- `)
-
- test(`
- abc(1)
- ---
-[
- {
- "Call": {
- "ArgumentList": [
- {
- "Literal": 1
- }
- ],
- "Callee": {
- "Identifier": "abc"
- }
- }
- }
-]
- `)
-
- test(`
- Math.pow(3, 2)
- ---
-[
- {
- "Call": {
- "ArgumentList": [
- {
- "Literal": 3
- },
- {
- "Literal": 2
- }
- ],
- "Callee": {
- "Dot": {
- "Left": {
- "Identifier": "Math"
- },
- "Member": "pow"
- }
- }
- }
- }
-]
- `)
-
- test(`
- 1, 2, 3
- ---
-[
- {
- "Sequence": [
- {
- "Literal": 1
- },
- {
- "Literal": 2
- },
- {
- "Literal": 3
- }
- ]
- }
-]
- `)
-
- test(`
- / abc / gim;
- ---
-[
- {
- "Literal": "/ abc / gim"
- }
-]
- `)
-
- test(`
- if (0)
- 1;
- ---
-[
- {
- "If": {
- "Consequent": {
- "Literal": 1
- },
- "Test": {
- "Literal": 0
- }
- }
- }
-]
- `)
-
- test(`
- 0+function(){
- return;
- }
- ---
-[
- {
- "BinaryExpression": {
- "Left": {
- "Literal": 0
- },
- "Operator": "+",
- "Right": {
- "Function": {
- "BlockStatement": [
- {
- "Return": null
- }
- ]
- }
- }
- }
- }
-]
- `)
-
- test(`
- xyzzy // Ignore it
- // Ignore this
- // And this
- /* And all..
-
-
-
- ... of this!
- */
- "Nothing happens."
- // And finally this
- ---
-[
- {
- "Identifier": "xyzzy"
- },
- {
- "Literal": "\"Nothing happens.\""
- }
-]
- `)
-
- test(`
- ((x & (x = 1)) !== 0)
- ---
-[
- {
- "BinaryExpression": {
- "Left": {
- "BinaryExpression": {
- "Left": {
- "Identifier": "x"
- },
- "Operator": "\u0026",
- "Right": {
- "Assign": {
- "Left": {
- "Identifier": "x"
- },
- "Right": {
- "Literal": 1
- }
- }
- }
- }
- },
- "Operator": "!==",
- "Right": {
- "Literal": 0
- }
- }
- }
-]
- `)
-
- test(`
- { abc: 'def' }
- ---
-[
- {
- "BlockStatement": [
- {
- "Label": {
- "Name": "abc",
- "Statement": {
- "Literal": "'def'"
- }
- }
- }
- ]
- }
-]
- `)
-
- test(`
- // This is not an object, this is a string literal with a label!
- ({ abc: 'def' })
- ---
-[
- {
- "Object": [
- {
- "Key": "abc",
- "Value": {
- "Literal": "'def'"
- }
- }
- ]
- }
-]
- `)
-
- test(`
- [,]
- ---
-[
- {
- "Array": [
- null
- ]
- }
-]
- `)
-
- test(`
- [,,]
- ---
-[
- {
- "Array": [
- null,
- null
- ]
- }
-]
- `)
-
- test(`
- ({ get abc() {} })
- ---
-[
- {
- "Object": [
- {
- "Key": "abc",
- "Value": {
- "Function": {
- "BlockStatement": []
- }
- }
- }
- ]
- }
-]
- `)
-
- test(`
- /abc/.source
- ---
-[
- {
- "Dot": {
- "Left": {
- "Literal": "/abc/"
- },
- "Member": "source"
- }
- }
-]
- `)
-
- test(`
- xyzzy
-
- throw new TypeError("Nothing happens.")
- ---
-[
- {
- "Identifier": "xyzzy"
- },
- {
- "Throw": {
- "New": {
- "ArgumentList": [
- {
- "Literal": "\"Nothing happens.\""
- }
- ],
- "Callee": {
- "Identifier": "TypeError"
- }
- }
- }
- }
-]
- `)
-
- // When run, this will call a type error to be thrown
- // This is essentially the same as:
- //
- // var abc = 1(function(){})()
- //
- test(`
- var abc = 1
- (function(){
- })()
- ---
-[
- {
- "Var": [
- [
- "abc",
- {
- "Call": {
- "ArgumentList": [],
- "Callee": {
- "Call": {
- "ArgumentList": [
- {
- "Function": {
- "BlockStatement": []
- }
- }
- ],
- "Callee": {
- "Literal": 1
- }
- }
- }
- }
- }
- ]
- ]
- }
-]
- `)
-
- test(`
- "use strict"
- ---
-[
- {
- "Literal": "\"use strict\""
- }
-]
- `)
-
- test(`
- "use strict"
- abc = 1 + 2 + 11
- ---
-[
- {
- "Literal": "\"use strict\""
- },
- {
- "Assign": {
- "Left": {
- "Identifier": "abc"
- },
- "Right": {
- "BinaryExpression": {
- "Left": {
- "BinaryExpression": {
- "Left": {
- "Literal": 1
- },
- "Operator": "+",
- "Right": {
- "Literal": 2
- }
- }
- },
- "Operator": "+",
- "Right": {
- "Literal": 11
- }
- }
- }
- }
- }
-]
- `)
-
- test(`
- abc = function() { 'use strict' }
- ---
-[
- {
- "Assign": {
- "Left": {
- "Identifier": "abc"
- },
- "Right": {
- "Function": {
- "BlockStatement": [
- {
- "Literal": "'use strict'"
- }
- ]
- }
- }
- }
- }
-]
- `)
-
- test(`
- for (var abc in def) {
- }
- ---
-[
- {
- "ForIn": {
- "Body": {
- "BlockStatement": []
- },
- "Into": [
- "abc",
- null
- ],
- "Source": {
- "Identifier": "def"
- }
- }
- }
-]
- `)
-
- test(`
- abc = {
- '"': "'",
- "'": '"',
- }
- ---
-[
- {
- "Assign": {
- "Left": {
- "Identifier": "abc"
- },
- "Right": {
- "Object": [
- {
- "Key": "\"",
- "Value": {
- "Literal": "\"'\""
- }
- },
- {
- "Key": "'",
- "Value": {
- "Literal": "'\"'"
- }
- }
- ]
- }
- }
- }
-]
- `)
-
- return
-
- test(`
- if (!abc && abc.jkl(def) && abc[0] === +abc[0] && abc.length < ghi) {
- }
- ---
-[
- {
- "If": {
- "Consequent": {
- "BlockStatement": []
- },
- "Test": {
- "BinaryExpression": {
- "Left": {
- "BinaryExpression": {
- "Left": {
- "BinaryExpression": {
- "Left": null,
- "Operator": "\u0026\u0026",
- "Right": {
- "Call": {
- "ArgumentList": [
- {
- "Identifier": "def"
- }
- ],
- "Callee": {
- "Dot": {
- "Left": {
- "Identifier": "abc"
- },
- "Member": "jkl"
- }
- }
- }
- }
- }
- },
- "Operator": "\u0026\u0026",
- "Right": {
- "BinaryExpression": {
- "Left": null,
- "Operator": "===",
- "Right": null
- }
- }
- }
- },
- "Operator": "\u0026\u0026",
- "Right": {
- "BinaryExpression": {
- "Left": {
- "Dot": {
- "Left": {
- "Identifier": "abc"
- },
- "Member": "length"
- }
- },
- "Operator": "\u003c",
- "Right": {
- "Identifier": "ghi"
- }
- }
- }
- }
- }
- }
- }
-]
- `)
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/parser.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/parser.go
index 1536344d7..92ac5b0c7 100644
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/parser.go
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/parser.go
@@ -52,7 +52,6 @@ const (
)
type _parser struct {
- filename string
str string
length int
base int
@@ -260,7 +259,7 @@ func (self *_parser) position(idx file.Idx) file.Position {
position := file.Position{}
offset := int(idx) - self.base
str := self.str[:offset]
- position.Filename = self.filename
+ position.Filename = self.file.Name()
line, last := lineCount(str)
position.Line = 1 + line
if last >= 0 {
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/parser_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/parser_test.go
deleted file mode 100644
index 8f9457745..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/parser_test.go
+++ /dev/null
@@ -1,1004 +0,0 @@
-package parser
-
-import (
- "errors"
- "regexp"
- "strings"
- "testing"
-
- "github.com/robertkrimen/otto/ast"
- "github.com/robertkrimen/otto/file"
-)
-
-func firstErr(err error) error {
- switch err := err.(type) {
- case ErrorList:
- return err[0]
- }
- return err
-}
-
-var matchBeforeAfterSeparator = regexp.MustCompile(`(?m)^[ \t]*---$`)
-
-func testParse(src string) (parser *_parser, program *ast.Program, err error) {
- defer func() {
- if tmp := recover(); tmp != nil {
- switch tmp := tmp.(type) {
- case string:
- if strings.HasPrefix(tmp, "SyntaxError:") {
- parser = nil
- program = nil
- err = errors.New(tmp)
- return
- }
- }
- panic(tmp)
- }
- }()
- parser = newParser("", src)
- program, err = parser.parse()
- return
-}
-
-func TestParseFile(t *testing.T) {
- tt(t, func() {
- _, err := ParseFile(nil, "", `/abc/`, 0)
- is(err, nil)
-
- _, err = ParseFile(nil, "", `/(?!def)abc/`, IgnoreRegExpErrors)
- is(err, nil)
-
- _, err = ParseFile(nil, "", `/(?!def)abc/`, 0)
- is(err, "(anonymous): Line 1:1 Invalid regular expression: re2: Invalid (?!) <lookahead>")
-
- _, err = ParseFile(nil, "", `/(?!def)abc/; return`, IgnoreRegExpErrors)
- is(err, "(anonymous): Line 1:15 Illegal return statement")
- })
-}
-
-func TestParseFunction(t *testing.T) {
- tt(t, func() {
- test := func(prm, bdy string, expect interface{}) *ast.FunctionLiteral {
- function, err := ParseFunction(prm, bdy)
- is(firstErr(err), expect)
- return function
- }
-
- test("a, b,c,d", "", nil)
-
- test("a, b;,c,d", "", "(anonymous): Line 1:15 Unexpected token ;")
-
- test("this", "", "(anonymous): Line 1:11 Unexpected token this")
-
- test("a, b, c, null", "", "(anonymous): Line 1:20 Unexpected token null")
-
- test("a, b,c,d", "return;", nil)
-
- test("a, b,c,d", "break;", "(anonymous): Line 2:1 Illegal break statement")
-
- test("a, b,c,d", "{}", nil)
- })
-}
-
-func TestParserErr(t *testing.T) {
- tt(t, func() {
- test := func(input string, expect interface{}) (*ast.Program, *_parser) {
- parser := newParser("", input)
- program, err := parser.parse()
- is(firstErr(err), expect)
- return program, parser
- }
-
- program, parser := test("", nil)
-
- program, parser = test(`
- var abc;
- break; do {
- } while(true);
- `, "(anonymous): Line 3:9 Illegal break statement")
- {
- stmt := program.Body[1].(*ast.BadStatement)
- is(parser.position(stmt.From).Column, 9)
- is(parser.position(stmt.To).Column, 16)
- is(parser.slice(stmt.From, stmt.To), "break; ")
- }
-
- test("{", "(anonymous): Line 1:2 Unexpected end of input")
-
- test("}", "(anonymous): Line 1:1 Unexpected token }")
-
- test("3ea", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("3in", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("3in []", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("3e", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("3e+", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("3e-", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("3x", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("3x0", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("0x", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("09", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("018", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("01.0", "(anonymous): Line 1:3 Unexpected number")
-
- test("01a", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("0x3in[]", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("\"Hello\nWorld\"", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("\u203f = 10", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("x\\", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("x\\\\", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("x\\u005c", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("x\\u002a", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("x\\\\u002a", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("/\n", "(anonymous): Line 1:1 Invalid regular expression: missing /")
-
- test("var x = /(s/g", "(anonymous): Line 1:9 Invalid regular expression: Unterminated group")
-
- test("0 = 1", "(anonymous): Line 1:1 Invalid left-hand side in assignment")
-
- test("func() = 1", "(anonymous): Line 1:1 Invalid left-hand side in assignment")
-
- test("(1 + 1) = 2", "(anonymous): Line 1:2 Invalid left-hand side in assignment")
-
- test("1++", "(anonymous): Line 1:2 Invalid left-hand side in assignment")
-
- test("1--", "(anonymous): Line 1:2 Invalid left-hand side in assignment")
-
- test("--1", "(anonymous): Line 1:1 Invalid left-hand side in assignment")
-
- test("for((1 + 1) in abc) def();", "(anonymous): Line 1:1 Invalid left-hand side in for-in")
-
- test("[", "(anonymous): Line 1:2 Unexpected end of input")
-
- test("[,", "(anonymous): Line 1:3 Unexpected end of input")
-
- test("1 + {", "(anonymous): Line 1:6 Unexpected end of input")
-
- test("1 + { abc:abc", "(anonymous): Line 1:14 Unexpected end of input")
-
- test("1 + { abc:abc,", "(anonymous): Line 1:15 Unexpected end of input")
-
- test("var abc = /\n/", "(anonymous): Line 1:11 Invalid regular expression: missing /")
-
- test("var abc = \"\n", "(anonymous): Line 1:11 Unexpected token ILLEGAL")
-
- test("var if = 0", "(anonymous): Line 1:5 Unexpected token if")
-
- test("abc + 0 = 1", "(anonymous): Line 1:1 Invalid left-hand side in assignment")
-
- test("+abc = 1", "(anonymous): Line 1:1 Invalid left-hand side in assignment")
-
- test("1 + (", "(anonymous): Line 1:6 Unexpected end of input")
-
- test("\n\n\n{", "(anonymous): Line 4:2 Unexpected end of input")
-
- test("\n/* Some multiline\ncomment */\n)", "(anonymous): Line 4:1 Unexpected token )")
-
- // TODO
- //{ set 1 }
- //{ get 2 }
- //({ set: s(if) { } })
- //({ set s(.) { } })
- //({ set: s() { } })
- //({ set: s(a, b) { } })
- //({ get: g(d) { } })
- //({ get i() { }, i: 42 })
- //({ i: 42, get i() { } })
- //({ set i(x) { }, i: 42 })
- //({ i: 42, set i(x) { } })
- //({ get i() { }, get i() { } })
- //({ set i(x) { }, set i(x) { } })
-
- test("function abc(if) {}", "(anonymous): Line 1:14 Unexpected token if")
-
- test("function abc(true) {}", "(anonymous): Line 1:14 Unexpected token true")
-
- test("function abc(false) {}", "(anonymous): Line 1:14 Unexpected token false")
-
- test("function abc(null) {}", "(anonymous): Line 1:14 Unexpected token null")
-
- test("function null() {}", "(anonymous): Line 1:10 Unexpected token null")
-
- test("function true() {}", "(anonymous): Line 1:10 Unexpected token true")
-
- test("function false() {}", "(anonymous): Line 1:10 Unexpected token false")
-
- test("function if() {}", "(anonymous): Line 1:10 Unexpected token if")
-
- test("a b;", "(anonymous): Line 1:3 Unexpected identifier")
-
- test("if.a", "(anonymous): Line 1:3 Unexpected token .")
-
- test("a if", "(anonymous): Line 1:3 Unexpected token if")
-
- test("a class", "(anonymous): Line 1:3 Unexpected reserved word")
-
- test("break\n", "(anonymous): Line 1:1 Illegal break statement")
-
- test("break 1;", "(anonymous): Line 1:7 Unexpected number")
-
- test("for (;;) { break 1; }", "(anonymous): Line 1:18 Unexpected number")
-
- test("continue\n", "(anonymous): Line 1:1 Illegal continue statement")
-
- test("continue 1;", "(anonymous): Line 1:10 Unexpected number")
-
- test("for (;;) { continue 1; }", "(anonymous): Line 1:21 Unexpected number")
-
- test("throw", "(anonymous): Line 1:1 Unexpected end of input")
-
- test("throw;", "(anonymous): Line 1:6 Unexpected token ;")
-
- test("throw \n", "(anonymous): Line 1:1 Unexpected end of input")
-
- test("for (var abc, def in {});", "(anonymous): Line 1:19 Unexpected token in")
-
- test("for ((abc in {});;);", nil)
-
- test("for ((abc in {}));", "(anonymous): Line 1:17 Unexpected token )")
-
- test("for (+abc in {});", "(anonymous): Line 1:1 Invalid left-hand side in for-in")
-
- test("if (false)", "(anonymous): Line 1:11 Unexpected end of input")
-
- test("if (false) abc(); else", "(anonymous): Line 1:23 Unexpected end of input")
-
- test("do", "(anonymous): Line 1:3 Unexpected end of input")
-
- test("while (false)", "(anonymous): Line 1:14 Unexpected end of input")
-
- test("for (;;)", "(anonymous): Line 1:9 Unexpected end of input")
-
- test("with (abc)", "(anonymous): Line 1:11 Unexpected end of input")
-
- test("try {}", "(anonymous): Line 1:1 Missing catch or finally after try")
-
- test("try {} catch {}", "(anonymous): Line 1:14 Unexpected token {")
-
- test("try {} catch () {}", "(anonymous): Line 1:15 Unexpected token )")
-
- test("\u203f = 1", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- // TODO
- // const x = 12, y;
- // const x, y = 12;
- // const x;
- // if(true) let a = 1;
- // if(true) const a = 1;
-
- test(`new abc()."def"`, "(anonymous): Line 1:11 Unexpected string")
-
- test("/*", "(anonymous): Line 1:3 Unexpected end of input")
-
- test("/**", "(anonymous): Line 1:4 Unexpected end of input")
-
- test("/*\n\n\n", "(anonymous): Line 4:1 Unexpected end of input")
-
- test("/*\n\n\n*", "(anonymous): Line 4:2 Unexpected end of input")
-
- test("/*abc", "(anonymous): Line 1:6 Unexpected end of input")
-
- test("/*abc *", "(anonymous): Line 1:9 Unexpected end of input")
-
- test("\n]", "(anonymous): Line 2:1 Unexpected token ]")
-
- test("\r\n]", "(anonymous): Line 2:1 Unexpected token ]")
-
- test("\n\r]", "(anonymous): Line 3:1 Unexpected token ]")
-
- test("//\r\n]", "(anonymous): Line 2:1 Unexpected token ]")
-
- test("//\n\r]", "(anonymous): Line 3:1 Unexpected token ]")
-
- test("/abc\\\n/", "(anonymous): Line 1:1 Invalid regular expression: missing /")
-
- test("//\r \n]", "(anonymous): Line 3:1 Unexpected token ]")
-
- test("/*\r\n*/]", "(anonymous): Line 2:3 Unexpected token ]")
-
- test("/*\r \n*/]", "(anonymous): Line 3:3 Unexpected token ]")
-
- test("\\\\", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("\\u005c", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("\\abc", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("\\u0000", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("\\u200c = []", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("\\u200D = []", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test(`"\`, "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test(`"\u`, "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("return", "(anonymous): Line 1:1 Illegal return statement")
-
- test("continue", "(anonymous): Line 1:1 Illegal continue statement")
-
- test("break", "(anonymous): Line 1:1 Illegal break statement")
-
- test("switch (abc) { default: continue; }", "(anonymous): Line 1:25 Illegal continue statement")
-
- test("do { abc } *", "(anonymous): Line 1:12 Unexpected token *")
-
- test("while (true) { break abc; }", "(anonymous): Line 1:16 Undefined label 'abc'")
-
- test("while (true) { continue abc; }", "(anonymous): Line 1:16 Undefined label 'abc'")
-
- test("abc: while (true) { (function(){ break abc; }); }", "(anonymous): Line 1:34 Undefined label 'abc'")
-
- test("abc: while (true) { (function(){ abc: break abc; }); }", nil)
-
- test("abc: while (true) { (function(){ continue abc; }); }", "(anonymous): Line 1:34 Undefined label 'abc'")
-
- test(`abc: if (0) break abc; else {}`, nil)
-
- test(`abc: if (0) { break abc; } else {}`, nil)
-
- test(`abc: if (0) { break abc } else {}`, nil)
-
- test("abc: while (true) { abc: while (true) {} }", "(anonymous): Line 1:21 Label 'abc' already exists")
-
- if false {
- // TODO When strict mode is implemented
- test("(function () { 'use strict'; delete abc; }())", "")
- }
-
- test("_: _: while (true) {]", "(anonymous): Line 1:4 Label '_' already exists")
-
- test("_:\n_:\nwhile (true) {]", "(anonymous): Line 2:1 Label '_' already exists")
-
- test("_:\n _:\nwhile (true) {]", "(anonymous): Line 2:4 Label '_' already exists")
-
- test("/Xyzzy(?!Nothing happens)/",
- "(anonymous): Line 1:1 Invalid regular expression: re2: Invalid (?!) <lookahead>")
-
- test("function(){}", "(anonymous): Line 1:9 Unexpected token (")
-
- test("\n/*/", "(anonymous): Line 2:4 Unexpected end of input")
-
- test("/*/.source", "(anonymous): Line 1:11 Unexpected end of input")
-
- test("/\\1/.source", "(anonymous): Line 1:1 Invalid regular expression: re2: Invalid \\1 <backreference>")
-
- test("var class", "(anonymous): Line 1:5 Unexpected reserved word")
-
- test("var if", "(anonymous): Line 1:5 Unexpected token if")
-
- test("object Object", "(anonymous): Line 1:8 Unexpected identifier")
-
- test("[object Object]", "(anonymous): Line 1:9 Unexpected identifier")
-
- test("\\u0xyz", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test(`for (var abc, def in {}) {}`, "(anonymous): Line 1:19 Unexpected token in")
-
- test(`for (abc, def in {}) {}`, "(anonymous): Line 1:1 Invalid left-hand side in for-in")
-
- test(`for (var abc=def, ghi=("abc" in {}); true;) {}`, nil)
-
- {
- // Semicolon insertion
-
- test("this\nif (1);", nil)
-
- test("while (1) { break\nif (1); }", nil)
-
- test("throw\nif (1);", "(anonymous): Line 1:1 Illegal newline after throw")
-
- test("(function(){ return\nif (1); })", nil)
-
- test("while (1) { continue\nif (1); }", nil)
-
- test("debugger\nif (1);", nil)
- }
-
- { // Reserved words
-
- test("class", "(anonymous): Line 1:1 Unexpected reserved word")
- test("abc.class = 1", nil)
- test("var class;", "(anonymous): Line 1:5 Unexpected reserved word")
-
- test("const", "(anonymous): Line 1:1 Unexpected reserved word")
- test("abc.const = 1", nil)
- test("var const;", "(anonymous): Line 1:5 Unexpected reserved word")
-
- test("enum", "(anonymous): Line 1:1 Unexpected reserved word")
- test("abc.enum = 1", nil)
- test("var enum;", "(anonymous): Line 1:5 Unexpected reserved word")
-
- test("export", "(anonymous): Line 1:1 Unexpected reserved word")
- test("abc.export = 1", nil)
- test("var export;", "(anonymous): Line 1:5 Unexpected reserved word")
-
- test("extends", "(anonymous): Line 1:1 Unexpected reserved word")
- test("abc.extends = 1", nil)
- test("var extends;", "(anonymous): Line 1:5 Unexpected reserved word")
-
- test("import", "(anonymous): Line 1:1 Unexpected reserved word")
- test("abc.import = 1", nil)
- test("var import;", "(anonymous): Line 1:5 Unexpected reserved word")
-
- test("super", "(anonymous): Line 1:1 Unexpected reserved word")
- test("abc.super = 1", nil)
- test("var super;", "(anonymous): Line 1:5 Unexpected reserved word")
- }
-
- { // Reserved words (strict)
-
- test(`implements`, nil)
- test(`abc.implements = 1`, nil)
- test(`var implements;`, nil)
-
- test(`interface`, nil)
- test(`abc.interface = 1`, nil)
- test(`var interface;`, nil)
-
- test(`let`, nil)
- test(`abc.let = 1`, nil)
- test(`var let;`, nil)
-
- test(`package`, nil)
- test(`abc.package = 1`, nil)
- test(`var package;`, nil)
-
- test(`private`, nil)
- test(`abc.private = 1`, nil)
- test(`var private;`, nil)
-
- test(`protected`, nil)
- test(`abc.protected = 1`, nil)
- test(`var protected;`, nil)
-
- test(`public`, nil)
- test(`abc.public = 1`, nil)
- test(`var public;`, nil)
-
- test(`static`, nil)
- test(`abc.static = 1`, nil)
- test(`var static;`, nil)
-
- test(`yield`, nil)
- test(`abc.yield = 1`, nil)
- test(`var yield;`, nil)
- }
- })
-}
-
-func TestParser(t *testing.T) {
- tt(t, func() {
- test := func(source string, chk interface{}) *ast.Program {
- _, program, err := testParse(source)
- is(firstErr(err), chk)
- return program
- }
-
- test(`
- abc
- --
- []
- `, "(anonymous): Line 3:13 Invalid left-hand side in assignment")
-
- test(`
- abc--
- []
- `, nil)
-
- test("1\n[]\n", "(anonymous): Line 2:2 Unexpected token ]")
-
- test(`
- function abc() {
- }
- abc()
- `, nil)
-
- program := test("", nil)
-
- test("//", nil)
-
- test("/* */", nil)
-
- test("/** **/", nil)
-
- test("/*****/", nil)
-
- test("/*", "(anonymous): Line 1:3 Unexpected end of input")
-
- test("#", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("/**/#", "(anonymous): Line 1:5 Unexpected token ILLEGAL")
-
- test("new +", "(anonymous): Line 1:5 Unexpected token +")
-
- program = test(";", nil)
- is(len(program.Body), 1)
- is(program.Body[0].(*ast.EmptyStatement).Semicolon, file.Idx(1))
-
- program = test(";;", nil)
- is(len(program.Body), 2)
- is(program.Body[0].(*ast.EmptyStatement).Semicolon, file.Idx(1))
- is(program.Body[1].(*ast.EmptyStatement).Semicolon, file.Idx(2))
-
- program = test("1.2", nil)
- is(len(program.Body), 1)
- is(program.Body[0].(*ast.ExpressionStatement).Expression.(*ast.NumberLiteral).Literal, "1.2")
-
- program = test("/* */1.2", nil)
- is(len(program.Body), 1)
- is(program.Body[0].(*ast.ExpressionStatement).Expression.(*ast.NumberLiteral).Literal, "1.2")
-
- program = test("\n", nil)
- is(len(program.Body), 0)
-
- test(`
- if (0) {
- abc = 0
- }
- else abc = 0
- `, nil)
-
- test("if (0) abc = 0 else abc = 0", "(anonymous): Line 1:16 Unexpected token else")
-
- test(`
- if (0) {
- abc = 0
- } else abc = 0
- `, nil)
-
- test(`
- if (0) {
- abc = 1
- } else {
- }
- `, nil)
-
- test(`
- do {
- } while (true)
- `, nil)
-
- test(`
- try {
- } finally {
- }
- `, nil)
-
- test(`
- try {
- } catch (abc) {
- } finally {
- }
- `, nil)
-
- test(`
- try {
- }
- catch (abc) {
- }
- finally {
- }
- `, nil)
-
- test(`try {} catch (abc) {} finally {}`, nil)
-
- test(`
- do {
- do {
- } while (0)
- } while (0)
- `, nil)
-
- test(`
- (function(){
- try {
- if (
- 1
- ) {
- return 1
- }
- return 0
- } finally {
- }
- })()
- `, nil)
-
- test("abc = ''\ndef", nil)
-
- test("abc = 1\ndef", nil)
-
- test("abc = Math\ndef", nil)
-
- test(`"\'"`, nil)
-
- test(`
- abc = function(){
- }
- abc = 0
- `, nil)
-
- test("abc.null = 0", nil)
-
- test("0x41", nil)
-
- test(`"\d"`, nil)
-
- test(`(function(){return this})`, nil)
-
- test(`
- Object.defineProperty(Array.prototype, "0", {
- value: 100,
- writable: false,
- configurable: true
- });
- abc = [101];
- abc.hasOwnProperty("0") && abc[0] === 101;
- `, nil)
-
- test(`new abc()`, nil)
- test(`new {}`, nil)
-
- test(`
- limit = 4
- result = 0
- while (limit) {
- limit = limit - 1
- if (limit) {
- }
- else {
- break
- }
- result = result + 1
- }
- `, nil)
-
- test(`
- while (0) {
- if (0) {
- continue
- }
- }
- `, nil)
-
- test("var \u0061\u0062\u0063 = 0", nil)
-
- // 7_3_1
- test("var test7_3_1\nabc = 66;", nil)
- test("var test7_3_1\u2028abc = 66;", nil)
-
- // 7_3_3
- test("//\u2028 =;", "(anonymous): Line 2:2 Unexpected token =")
-
- // 7_3_10
- test("var abc = \u2029;", "(anonymous): Line 2:1 Unexpected token ;")
- test("var abc = \\u2029;", "(anonymous): Line 1:11 Unexpected token ILLEGAL")
- test("var \\u0061\\u0062\\u0063 = 0;", nil)
-
- test("'", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- test("'\nstr\ning\n'", "(anonymous): Line 1:1 Unexpected token ILLEGAL")
-
- // S7.6_A4.3_T1
- test(`var $\u0030 = 0;`, nil)
-
- // S7.6.1.1_A1.1
- test(`switch = 1`, "(anonymous): Line 1:8 Unexpected token =")
-
- // S7.8.3_A2.1_T1
- test(`.0 === 0.0`, nil)
-
- // 7.8.5-1
- test("var regExp = /\\\rn/;", "(anonymous): Line 1:14 Invalid regular expression: missing /")
-
- // S7.8.5_A1.1_T2
- test("var regExp = /=/;", nil)
-
- // S7.8.5_A1.2_T1
- test("/*/", "(anonymous): Line 1:4 Unexpected end of input")
-
- // Sbp_7.9_A9_T3
- test(`
- do {
- ;
- } while (false) true
- `, nil)
-
- // S7.9_A10_T10
- test(`
- {a:1
- } 3
- `, nil)
-
- test(`
- abc
- ++def
- `, nil)
-
- // S7.9_A5.2_T1
- test(`
- for(false;false
- ) {
- break;
- }
- `, "(anonymous): Line 3:13 Unexpected token )")
-
- // S7.9_A9_T8
- test(`
- do {};
- while (false)
- `, "(anonymous): Line 2:18 Unexpected token ;")
-
- // S8.4_A5
- test(`
- "x\0y"
- `, nil)
-
- // S9.3.1_A6_T1
- test(`
- 10e10000
- `, nil)
-
- // 10.4.2-1-5
- test(`
- "abc\
- def"
- `, nil)
-
- test("'\\\n'", nil)
-
- test("'\\\r\n'", nil)
-
- //// 11.13.1-1-1
- test("42 = 42;", "(anonymous): Line 1:1 Invalid left-hand side in assignment")
-
- // S11.13.2_A4.2_T1.3
- test(`
- abc /= "1"
- `, nil)
-
- // 12.1-1
- test(`
- try{};catch(){}
- `, "(anonymous): Line 2:13 Missing catch or finally after try")
-
- // 12.1-3
- test(`
- try{};finally{}
- `, "(anonymous): Line 2:13 Missing catch or finally after try")
-
- // S12.6.3_A11.1_T3
- test(`
- while (true) {
- break abc;
- }
- `, "(anonymous): Line 3:17 Undefined label 'abc'")
-
- // S15.3_A2_T1
- test(`var x / = 1;`, "(anonymous): Line 1:7 Unexpected token /")
-
- test(`
- function abc() {
- if (0)
- return;
- else {
- }
- }
- `, nil)
-
- test("//\u2028 var =;", "(anonymous): Line 2:6 Unexpected token =")
-
- test(`
- throw
- {}
- `, "(anonymous): Line 2:13 Illegal newline after throw")
-
- // S7.6.1.1_A1.11
- test(`
- function = 1
- `, "(anonymous): Line 2:22 Unexpected token =")
-
- // S7.8.3_A1.2_T1
- test(`0e1`, nil)
-
- test("abc = 1; abc\n++", "(anonymous): Line 2:3 Unexpected end of input")
-
- // ---
-
- test("({ get abc() {} })", nil)
-
- test(`for (abc.def in {}) {}`, nil)
-
- test(`while (true) { break }`, nil)
-
- test(`while (true) { continue }`, nil)
-
- test(`abc=/^(?:(\w+:)\/{2}(\w+(?:\.\w+)*\/?)|(.{0,2}\/{1}))?([/.]*?(?:[^?]+)?\/)?((?:[^/?]+)\.(\w+))(?:\?(\S+)?)?$/,def=/^(?:(\w+:)\/{2})|(.{0,2}\/{1})?([/.]*?(?:[^?]+)?\/?)?$/`, nil)
-
- test(`(function() { try {} catch (err) {} finally {} return })`, nil)
-
- test(`0xde0b6b3a7640080.toFixed(0)`, nil)
-
- test(`/[^-._0-9A-Za-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u37f-\u1fff\u200c-\u200d\u203f\u2040\u2070-\u218f]/`, nil)
-
- test(`/[\u0000-\u0008\u000B-\u000C\u000E-\u001F\uD800-\uDFFF\uFFFE-\uFFFF]/`, nil)
-
- test("var abc = 1;\ufeff", nil)
-
- test("\ufeff/* var abc = 1; */", nil)
-
- test(`if (-0x8000000000000000<=abc&&abc<=0x8000000000000000) {}`, nil)
-
- test(`(function(){debugger;return this;})`, nil)
-
- test(`
-
- `, nil)
-
- test(`
- var abc = ""
- debugger
- `, nil)
-
- test(`
- var abc = /\[\]$/
- debugger
- `, nil)
-
- test(`
- var abc = 1 /
- 2
- debugger
- `, nil)
- })
-}
-
-func Test_parseStringLiteral(t *testing.T) {
- tt(t, func() {
- test := func(have, want string) {
- have, err := parseStringLiteral(have)
- is(err, nil)
- is(have, want)
- }
-
- test("", "")
-
- test("1(\\\\d+)", "1(\\d+)")
-
- test("\\u2029", "\u2029")
-
- test("abc\\uFFFFabc", "abc\uFFFFabc")
-
- test("[First line \\\nSecond line \\\n Third line\\\n. ]",
- "[First line Second line Third line. ]")
-
- test("\\u007a\\x79\\u000a\\x78", "zy\nx")
-
- // S7.8.4_A4.2_T3
- test("\\a", "a")
- test("\u0410", "\u0410")
-
- // S7.8.4_A5.1_T1
- test("\\0", "\u0000")
-
- // S8.4_A5
- test("\u0000", "\u0000")
-
- // 15.5.4.20
- test("'abc'\\\n'def'", "'abc''def'")
-
- // 15.5.4.20-4-1
- test("'abc'\\\r\n'def'", "'abc''def'")
-
- // Octal
- test("\\0", "\000")
- test("\\00", "\000")
- test("\\000", "\000")
- test("\\09", "\0009")
- test("\\009", "\0009")
- test("\\0009", "\0009")
- test("\\1", "\001")
- test("\\01", "\001")
- test("\\001", "\001")
- test("\\0011", "\0011")
- test("\\1abc", "\001abc")
-
- test("\\\u4e16", "\u4e16")
-
- // err
- test = func(have, want string) {
- have, err := parseStringLiteral(have)
- is(err.Error(), want)
- is(have, "")
- }
-
- test(`\u`, `invalid escape: \u: len("") != 4`)
- test(`\u0`, `invalid escape: \u: len("0") != 4`)
- test(`\u00`, `invalid escape: \u: len("00") != 4`)
- test(`\u000`, `invalid escape: \u: len("000") != 4`)
-
- test(`\x`, `invalid escape: \x: len("") != 2`)
- test(`\x0`, `invalid escape: \x: len("0") != 2`)
- test(`\x0`, `invalid escape: \x: len("0") != 2`)
- })
-}
-
-func Test_parseNumberLiteral(t *testing.T) {
- tt(t, func() {
- test := func(input string, expect interface{}) {
- result, err := parseNumberLiteral(input)
- is(err, nil)
- is(result, expect)
- }
-
- test("0", 0)
-
- test("0x8000000000000000", float64(9.223372036854776e+18))
- })
-}
-
-func TestPosition(t *testing.T) {
- tt(t, func() {
- parser := newParser("", "// Lorem ipsum")
-
- // Out of range, idx0 (error condition)
- is(parser.slice(0, 1), "")
- is(parser.slice(0, 10), "")
-
- // Out of range, idx1 (error condition)
- is(parser.slice(1, 128), "")
-
- is(parser.str[0:0], "")
- is(parser.slice(1, 1), "")
-
- is(parser.str[0:1], "/")
- is(parser.slice(1, 2), "/")
-
- is(parser.str[0:14], "// Lorem ipsum")
- is(parser.slice(1, 15), "// Lorem ipsum")
-
- parser = newParser("", "(function(){ return 0; })")
- program, err := parser.parse()
- is(err, nil)
-
- var node ast.Node
- node = program.Body[0].(*ast.ExpressionStatement).Expression.(*ast.FunctionLiteral)
- is(node.Idx0(), file.Idx(2))
- is(node.Idx1(), file.Idx(25))
- is(parser.slice(node.Idx0(), node.Idx1()), "function(){ return 0; }")
- is(parser.slice(node.Idx0(), node.Idx1()+1), "function(){ return 0; })")
- is(parser.slice(node.Idx0(), node.Idx1()+2), "")
- is(node.(*ast.FunctionLiteral).Source, "function(){ return 0; }")
-
- node = program
- is(node.Idx0(), file.Idx(2))
- is(node.Idx1(), file.Idx(25))
- is(parser.slice(node.Idx0(), node.Idx1()), "function(){ return 0; }")
-
- parser = newParser("", "(function(){ return abc; })")
- program, err = parser.parse()
- is(err, nil)
- node = program.Body[0].(*ast.ExpressionStatement).Expression.(*ast.FunctionLiteral)
- is(node.(*ast.FunctionLiteral).Source, "function(){ return abc; }")
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/regexp_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/regexp_test.go
deleted file mode 100644
index 3222db1a7..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser/regexp_test.go
+++ /dev/null
@@ -1,149 +0,0 @@
-package parser
-
-import (
- "regexp"
- "testing"
-)
-
-func TestRegExp(t *testing.T) {
- tt(t, func() {
- {
- // err
- test := func(input string, expect interface{}) {
- _, err := TransformRegExp(input)
- is(err, expect)
- }
-
- test("[", "Unterminated character class")
-
- test("(", "Unterminated group")
-
- test("(?=)", "re2: Invalid (?=) <lookahead>")
-
- test("(?=)", "re2: Invalid (?=) <lookahead>")
-
- test("(?!)", "re2: Invalid (?!) <lookahead>")
-
- // An error anyway
- test("(?=", "re2: Invalid (?=) <lookahead>")
-
- test("\\1", "re2: Invalid \\1 <backreference>")
-
- test("\\90", "re2: Invalid \\90 <backreference>")
-
- test("\\9123456789", "re2: Invalid \\9123456789 <backreference>")
-
- test("\\(?=)", "Unmatched ')'")
-
- test(")", "Unmatched ')'")
- }
-
- {
- // err
- test := func(input, expect string, expectErr interface{}) {
- output, err := TransformRegExp(input)
- is(output, expect)
- is(err, expectErr)
- }
-
- test("(?!)", "(?!)", "re2: Invalid (?!) <lookahead>")
-
- test(")", "", "Unmatched ')'")
-
- test("(?!))", "", "re2: Invalid (?!) <lookahead>")
-
- test("\\0", "\\0", nil)
-
- test("\\1", "\\1", "re2: Invalid \\1 <backreference>")
-
- test("\\9123456789", "\\9123456789", "re2: Invalid \\9123456789 <backreference>")
- }
-
- {
- // err
- test := func(input string, expect string) {
- result, err := TransformRegExp(input)
- is(err, nil)
- if is(result, expect) {
- _, err := regexp.Compile(result)
- if !is(err, nil) {
- t.Log(result)
- }
- }
- }
-
- test("", "")
-
- test("abc", "abc")
-
- test(`\abc`, `abc`)
-
- test(`\a\b\c`, `a\bc`)
-
- test(`\x`, `x`)
-
- test(`\c`, `c`)
-
- test(`\cA`, `\x01`)
-
- test(`\cz`, `\x1a`)
-
- test(`\ca`, `\x01`)
-
- test(`\cj`, `\x0a`)
-
- test(`\ck`, `\x0b`)
-
- test(`\+`, `\+`)
-
- test(`[\b]`, `[\x08]`)
-
- test(`\u0z01\x\undefined`, `u0z01xundefined`)
-
- test(`\\|'|\r|\n|\t|\u2028|\u2029`, `\\|'|\r|\n|\t|\x{2028}|\x{2029}`)
-
- test("]", "]")
-
- test("}", "}")
-
- test("%", "%")
-
- test("(%)", "(%)")
-
- test("(?:[%\\s])", "(?:[%\\s])")
-
- test("[[]", "[[]")
-
- test("\\101", "\\x41")
-
- test("\\51", "\\x29")
-
- test("\\051", "\\x29")
-
- test("\\175", "\\x7d")
-
- test("\\04", "\\x04")
-
- test(`<%([\s\S]+?)%>`, `<%([\s\S]+?)%>`)
-
- test(`(.)^`, "(.)^")
-
- test(`<%-([\s\S]+?)%>|<%=([\s\S]+?)%>|<%([\s\S]+?)%>|$`, `<%-([\s\S]+?)%>|<%=([\s\S]+?)%>|<%([\s\S]+?)%>|$`)
-
- test(`\$`, `\$`)
-
- test(`[G-b]`, `[G-b]`)
-
- test(`[G-b\0]`, `[G-b\0]`)
- }
- })
-}
-
-func TestTransformRegExp(t *testing.T) {
- tt(t, func() {
- pattern, err := TransformRegExp(`\s+abc\s+`)
- is(err, nil)
- is(pattern, `\s+abc\s+`)
- is(regexp.MustCompile(pattern).MatchString("\t abc def"), true)
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/parser_test.go
deleted file mode 100644
index 7db43d239..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/parser_test.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package otto
-
-import (
- "testing"
-)
-
-func TestPersistence(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- function abc() { return 1; }
- abc.toString();
- `, "function abc() { return 1; }")
-
- test(`
- function def() { return 3.14159; }
- [ abc.toString(), def.toString() ];
- `, "function abc() { return 1; },function def() { return 3.14159; }")
-
- test(`
- eval("function ghi() { return 'ghi' }");
- [ abc.toString(), def.toString(), ghi.toString() ];
- `, "function abc() { return 1; },function def() { return 3.14159; },function ghi() { return 'ghi' }")
-
- test(`
- [ abc.toString(), def.toString(), ghi.toString() ];
- `, "function abc() { return 1; },function def() { return 3.14159; },function ghi() { return 'ghi' }")
-
- test(`/*
-
-
-
-
-
-
-
-
-
- */`, UndefinedValue())
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/reflect_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/reflect_test.go
deleted file mode 100644
index e4e83adeb..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/reflect_test.go
+++ /dev/null
@@ -1,483 +0,0 @@
-package otto
-
-import (
- "math"
- "reflect"
- "testing"
-)
-
-type _abcStruct struct {
- Abc bool
- Def int
- Ghi string
- Jkl interface{}
- Mno _mnoStruct
- Pqr map[string]int8
-}
-
-func (abc _abcStruct) String() string {
- return abc.Ghi
-}
-
-func (abc *_abcStruct) FuncPointer() string {
- return "abc"
-}
-
-func (abc _abcStruct) Func() {
- return
-}
-
-func (abc _abcStruct) FuncReturn1() string {
- return "abc"
-}
-
-func (abc _abcStruct) FuncReturn2() (string, error) {
- return "def", nil
-}
-
-func (abc _abcStruct) Func1Return1(a string) string {
- return a
-}
-
-func (abc _abcStruct) Func2Return1(x, y string) string {
- return x + y
-}
-
-func (abc _abcStruct) FuncEllipsis(xyz ...string) int {
- return len(xyz)
-}
-
-func (abc _abcStruct) FuncReturnStruct() _mnoStruct {
- return _mnoStruct{}
-}
-
-type _mnoStruct struct {
- Ghi string
-}
-
-func (mno _mnoStruct) Func() string {
- return "mno"
-}
-
-func TestReflect(t *testing.T) {
- if true {
- return
- }
- tt(t, func() {
- // Testing dbgf
- // These should panic
- toValue("Xyzzy").toReflectValue(reflect.Ptr)
- stringToReflectValue("Xyzzy", reflect.Ptr)
- })
-}
-
-func Test_reflectStruct(t *testing.T) {
- tt(t, func() {
- test, vm := test()
-
- // _abcStruct
- {
- abc := &_abcStruct{}
- vm.Set("abc", abc)
-
- test(`
- [ abc.Abc, abc.Ghi ];
- `, "false,")
-
- abc.Abc = true
- abc.Ghi = "Nothing happens."
-
- test(`
- [ abc.Abc, abc.Ghi ];
- `, "true,Nothing happens.")
-
- *abc = _abcStruct{}
-
- test(`
- [ abc.Abc, abc.Ghi ];
- `, "false,")
-
- abc.Abc = true
- abc.Ghi = "Xyzzy"
- vm.Set("abc", abc)
-
- test(`
- [ abc.Abc, abc.Ghi ];
- `, "true,Xyzzy")
-
- is(abc.Abc, true)
- test(`
- abc.Abc = false;
- abc.Def = 451;
- abc.Ghi = "Nothing happens.";
- abc.abc = "Something happens.";
- [ abc.Def, abc.abc ];
- `, "451,Something happens.")
- is(abc.Abc, false)
- is(abc.Def, 451)
- is(abc.Ghi, "Nothing happens.")
-
- test(`
- delete abc.Def;
- delete abc.abc;
- [ abc.Def, abc.abc ];
- `, "451,")
- is(abc.Def, 451)
-
- test(`
- abc.FuncPointer();
- `, "abc")
-
- test(`
- abc.Func();
- `, "undefined")
-
- test(`
- abc.FuncReturn1();
- `, "abc")
-
- test(`
- abc.Func1Return1("abc");
- `, "abc")
-
- test(`
- abc.Func2Return1("abc", "def");
- `, "abcdef")
-
- test(`
- abc.FuncEllipsis("abc", "def", "ghi");
- `, 3)
-
- test(`raise:
- abc.FuncReturn2();
- `, "TypeError")
-
- test(`
- abc.FuncReturnStruct();
- `, "[object Object]")
-
- test(`
- abc.FuncReturnStruct().Func();
- `, "mno")
- }
- })
-}
-
-func Test_reflectMap(t *testing.T) {
- tt(t, func() {
- test, vm := test()
-
- // map[string]string
- {
- abc := map[string]string{
- "Xyzzy": "Nothing happens.",
- "def": "1",
- }
- vm.Set("abc", abc)
-
- test(`
- abc.xyz = "pqr";
- [ abc.Xyzzy, abc.def, abc.ghi ];
- `, "Nothing happens.,1,")
-
- is(abc["xyz"], "pqr")
- }
-
- // map[string]float64
- {
- abc := map[string]float64{
- "Xyzzy": math.Pi,
- "def": 1,
- }
- vm.Set("abc", abc)
-
- test(`
- abc.xyz = "pqr";
- abc.jkl = 10;
- [ abc.Xyzzy, abc.def, abc.ghi ];
- `, "3.141592653589793,1,")
-
- is(abc["xyz"], math.NaN())
- is(abc["jkl"], float64(10))
- }
-
- // map[string]int32
- {
- abc := map[string]int32{
- "Xyzzy": 3,
- "def": 1,
- }
- vm.Set("abc", abc)
-
- test(`
- abc.xyz = "pqr";
- abc.jkl = 10;
- [ abc.Xyzzy, abc.def, abc.ghi ];
- `, "3,1,")
-
- is(abc["xyz"], 0)
- is(abc["jkl"], int32(10))
-
- test(`
- delete abc["Xyzzy"];
- `)
-
- _, exists := abc["Xyzzy"]
- is(exists, false)
- is(abc["Xyzzy"], 0)
- }
-
- // map[int32]string
- {
- abc := map[int32]string{
- 0: "abc",
- 1: "def",
- }
- vm.Set("abc", abc)
-
- test(`
- abc[2] = "pqr";
- //abc.jkl = 10;
- abc[3] = 10;
- [ abc[0], abc[1], abc[2], abc[3] ]
- `, "abc,def,pqr,10")
-
- is(abc[2], "pqr")
- is(abc[3], "10")
-
- test(`
- delete abc[2];
- `)
-
- _, exists := abc[2]
- is(exists, false)
- }
-
- })
-}
-
-func Test_reflectSlice(t *testing.T) {
- tt(t, func() {
- test, vm := test()
-
- // []bool
- {
- abc := []bool{
- false,
- true,
- true,
- false,
- }
- vm.Set("abc", abc)
-
- test(`
- abc;
- `, "false,true,true,false")
-
- test(`
- abc[0] = true;
- abc[abc.length-1] = true;
- delete abc[2];
- abc;
- `, "true,true,false,true")
-
- is(abc, []bool{true, true, false, true})
- is(abc[len(abc)-1], true)
- }
-
- // []int32
- {
- abc := make([]int32, 4)
- vm.Set("abc", abc)
-
- test(`
- abc;
- `, "0,0,0,0")
-
- test(`
- abc[0] = 4.2;
- abc[1] = "42";
- abc[2] = 3.14;
- abc;
- `, "4,42,3,0")
-
- is(abc, []int32{4, 42, 3, 0})
-
- test(`
- delete abc[1];
- delete abc[2];
- `)
- is(abc[1], 0)
- is(abc[2], 0)
- }
- })
-}
-
-func Test_reflectArray(t *testing.T) {
- tt(t, func() {
- test, vm := test()
-
- // []bool
- {
- abc := [4]bool{
- false,
- true,
- true,
- false,
- }
- vm.Set("abc", abc)
-
- test(`
- abc;
- `, "false,true,true,false")
- // Unaddressable array
-
- test(`
- abc[0] = true;
- abc[abc.length-1] = true;
- abc;
- `, "false,true,true,false")
- // Again, unaddressable array
-
- is(abc, [4]bool{false, true, true, false})
- is(abc[len(abc)-1], false)
- // ...
- }
-
- // []int32
- {
- abc := make([]int32, 4)
- vm.Set("abc", abc)
-
- test(`
- abc;
- `, "0,0,0,0")
-
- test(`
- abc[0] = 4.2;
- abc[1] = "42";
- abc[2] = 3.14;
- abc;
- `, "4,42,3,0")
-
- is(abc, []int32{4, 42, 3, 0})
- }
-
- // []bool
- {
- abc := [4]bool{
- false,
- true,
- true,
- false,
- }
- vm.Set("abc", &abc)
-
- test(`
- abc;
- `, "false,true,true,false")
-
- test(`
- abc[0] = true;
- abc[abc.length-1] = true;
- delete abc[2];
- abc;
- `, "true,true,false,true")
-
- is(abc, [4]bool{true, true, false, true})
- is(abc[len(abc)-1], true)
- }
-
- })
-}
-
-func Test_reflectArray_concat(t *testing.T) {
- tt(t, func() {
- test, vm := test()
-
- vm.Set("ghi", []string{"jkl", "mno"})
- vm.Set("pqr", []interface{}{"jkl", 42, 3.14159, true})
- test(`
- var def = {
- "abc": ["abc"],
- "xyz": ["xyz"]
- };
- xyz = pqr.concat(ghi, def.abc, def, def.xyz);
- [ xyz, xyz.length ];
- `, "jkl,42,3.14159,true,jkl,mno,abc,[object Object],xyz,9")
- })
-}
-
-func Test_reflectMapInterface(t *testing.T) {
- tt(t, func() {
- test, vm := test()
-
- {
- abc := map[string]interface{}{
- "Xyzzy": "Nothing happens.",
- "def": "1",
- "jkl": "jkl",
- }
- vm.Set("abc", abc)
- vm.Set("mno", &_abcStruct{})
-
- test(`
- abc.xyz = "pqr";
- abc.ghi = {};
- abc.jkl = 3.14159;
- abc.mno = mno;
- mno.Abc = true;
- mno.Ghi = "Something happens.";
- [ abc.Xyzzy, abc.def, abc.ghi, abc.mno ];
- `, "Nothing happens.,1,[object Object],[object Object]")
-
- is(abc["xyz"], "pqr")
- is(abc["ghi"], "[object Object]")
- is(abc["jkl"], float64(3.14159))
- mno, valid := abc["mno"].(*_abcStruct)
- is(valid, true)
- is(mno.Abc, true)
- is(mno.Ghi, "Something happens.")
- }
- })
-}
-
-func TestPassthrough(t *testing.T) {
- tt(t, func() {
- test, vm := test()
-
- {
- abc := &_abcStruct{
- Mno: _mnoStruct{
- Ghi: "<Mno.Ghi>",
- },
- }
- vm.Set("abc", abc)
-
- test(`
- abc.Mno.Ghi;
- `, "<Mno.Ghi>")
-
- vm.Set("pqr", map[string]int8{
- "xyzzy": 0,
- "Nothing happens.": 1,
- })
-
- test(`
- abc.Ghi = "abc";
- abc.Pqr = pqr;
- abc.Pqr["Nothing happens."];
- `, 1)
-
- mno := _mnoStruct{
- Ghi: "<mno.Ghi>",
- }
- vm.Set("mno", mno)
-
- test(`
- abc.Mno = mno;
- abc.Mno.Ghi;
- `, "<mno.Ghi>")
- }
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/regexp_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/regexp_test.go
deleted file mode 100644
index 8e65ee46a..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/regexp_test.go
+++ /dev/null
@@ -1,290 +0,0 @@
-package otto
-
-import (
- "fmt"
- "testing"
-)
-
-func TestRegExp(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- [
- /abc/.toString(),
- /abc/gim.toString(),
- ""+/abc/gi.toString(),
- new RegExp("1(\\d+)").toString(),
- ];
- `, "/abc/,/abc/gim,/abc/gi,/1(\\d+)/")
-
- test(`
- [
- new RegExp("abc").exec("123abc456"),
- null === new RegExp("xyzzy").exec("123abc456"),
- new RegExp("1(\\d+)").exec("123abc456"),
- new RegExp("xyzzy").test("123abc456"),
- new RegExp("1(\\d+)").test("123abc456"),
- new RegExp("abc").exec("123abc456"),
- ];
- `, "abc,true,123,23,false,true,abc")
-
- test(`new RegExp("abc").toString()`, "/abc/")
- test(`new RegExp("abc", "g").toString()`, "/abc/g")
- test(`new RegExp("abc", "mig").toString()`, "/abc/gim")
-
- result := test(`/(a)?/.exec('b')`, ",")
- is(result._object().get("0"), "")
- is(result._object().get("1"), "undefined")
- is(result._object().get("length"), 2)
-
- result = test(`/(a)?(b)?/.exec('b')`, "b,,b")
- is(result._object().get("0"), "b")
- is(result._object().get("1"), "undefined")
- is(result._object().get("2"), "b")
- is(result._object().get("length"), 3)
-
- test(`/\u0041/.source`, "\\u0041")
- test(`/\a/.source`, "\\a")
- test(`/\;/.source`, "\\;")
-
- test(`/a\a/.source`, "a\\a")
- test(`/,\;/.source`, ",\\;")
- test(`/ \ /.source`, " \\ ")
-
- // Start sanity check...
- test("eval(\"/abc/\").source", "abc")
- test("eval(\"/\u0023/\").source", "#")
- test("eval(\"/\u0058/\").source", "X")
- test("eval(\"/\\\u0023/\").source == \"\\\u0023\"", true)
- test("'0x' + '0058'", "0x0058")
- test("'\\\\' + '0x' + '0058'", "\\0x0058")
- // ...stop sanity check
-
- test(`abc = '\\' + String.fromCharCode('0x' + '0058'); eval('/' + abc + '/').source`, "\\X")
- test(`abc = '\\' + String.fromCharCode('0x0058'); eval('/' + abc + '/').source == "\\\u0058"`, true)
- test(`abc = '\\' + String.fromCharCode('0x0023'); eval('/' + abc + '/').source == "\\\u0023"`, true)
- test(`abc = '\\' + String.fromCharCode('0x0078'); eval('/' + abc + '/').source == "\\\u0078"`, true)
-
- test(`
- var abc = Object.getOwnPropertyDescriptor(RegExp, "prototype");
- [ [ typeof RegExp.prototype ],
- [ abc.writable, abc.enumerable, abc.configurable ] ];
- `, "object,false,false,false")
- })
-}
-
-func TestRegExp_global(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var abc = /(?:ab|cd)\d?/g;
- var found = [];
- do {
- match = abc.exec("ab cd2 ab34 cd");
- if (match !== null) {
- found.push(match[0]);
- } else {
- break;
- }
- } while (true);
- found;
- `, "ab,cd2,ab3,cd")
- })
-}
-
-func TestRegExp_exec(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- abc = /./g;
- def = '123456';
- ghi = 0;
- while (ghi < 100 && abc.exec(def) !== null) {
- ghi += 1;
- }
- [ ghi, def.length, ghi == def.length ];
- `, "6,6,true")
-
- test(`
- abc = /[abc](\d)?/g;
- def = 'a0 b c1 d3';
- ghi = 0;
- lastIndex = 0;
- while (ghi < 100 && abc.exec(def) !== null) {
- lastIndex = abc.lastIndex;
- ghi += 1;
-
- }
- [ ghi, lastIndex ];
- `, "3,7")
-
- test(`
- var abc = /[abc](\d)?/.exec("a0 b c1 d3");
- [ abc.length, abc.input, abc.index, abc ];
- `, "2,a0 b c1 d3,0,a0,0")
-
- test(`raise:
- var exec = RegExp.prototype.exec;
- exec("Xyzzy");
- `, "TypeError: Calling RegExp.exec on a non-RegExp object")
-
- test(`
- var abc = /\w{3}\d?/.exec("CE\uFFFFL\uFFDDbox127");
- [ abc.input.length, abc.length, abc.input, abc.index, abc ];
- `, "11,1,CE\uFFFFL\uFFDDbox127,5,box1")
-
- test(`RegExp.prototype.exec.length`, 1)
- test(`RegExp.prototype.exec.prototype`, "undefined")
- })
-}
-
-func TestRegExp_test(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`RegExp.prototype.test.length`, 1)
- test(`RegExp.prototype.test.prototype`, "undefined")
- })
-}
-
-func TestRegExp_toString(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`RegExp.prototype.toString.length`, 0)
- test(`RegExp.prototype.toString.prototype`, "undefined")
- })
-}
-
-func TestRegExp_zaacbbbcac(t *testing.T) {
- if true {
- return
- }
-
- tt(t, func() {
- test, _ := test()
-
- // FIXME? TODO /(z)((a+)?(b+)?(c))*/.exec("zaacbbbcac")
- test(`
- var abc = /(z)((a+)?(b+)?(c))*/.exec("zaacbbbcac");
- [ abc.length, abc.index, abc ];
- `, "6,0,zaacbbbcac,z,ac,a,,c")
- })
-}
-
-func TestRegExpCopying(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- abc = /xyzzy/i;
- def = RegExp(abc);
- abc.indicator = 1;
- [ abc.indicator, def.indicator ];
- `, "1,1")
-
- test(`raise:
- RegExp(new RegExp("\\d"), "1");
- `, "TypeError: Cannot supply flags when constructing one RegExp from another")
- })
-}
-
-func TestRegExp_multiline(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var abc = /s$/m.exec("pairs\nmakes\tdouble");
- [ abc.length, abc.index, abc ];
- `, "1,4,s")
- })
-}
-
-func TestRegExp_source(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- [ /xyzzy/i.source, /./i.source ];
- `, "xyzzy,.")
-
- test(`
- var abc = /./i;
- var def = new RegExp(abc);
- [ abc.source, def.source, abc.source === def.source ];
- `, ".,.,true")
-
- test(`
- var abc = /./i;
- var def = abc.hasOwnProperty("source");
- var ghi = abc.source;
- abc.source = "xyzzy";
- [ def, abc.source ];
- `, "true,.")
- })
-}
-
-func TestRegExp_newRegExp(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- Math.toString();
- var abc = new RegExp(Math,eval("\"g\""));
- [ abc, abc.global ];
- `, "/[object Math]/g,true")
- })
-}
-
-func TestRegExp_flags(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var abc = /./i;
- var def = new RegExp(abc);
- [ abc.multiline == def.multiline, abc.global == def.global, abc.ignoreCase == def.ignoreCase ];
- `, "true,true,true")
- })
-}
-
-func TestRegExp_controlCharacter(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- for code := 0x41; code < 0x5a; code++ {
- string_ := string(code - 64)
- test(fmt.Sprintf(`
- var code = 0x%x;
- var string = String.fromCharCode(code %% 32);
- var result = (new RegExp("\\c" + String.fromCharCode(code))).exec(string);
- [ code, string, result ];
- `, code), fmt.Sprintf("%d,%s,%s", code, string_, string_))
- }
- })
-}
-
-func TestRegExp_notNotEmptyCharacterClass(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var abc = /[\s\S]a/m.exec("a\naba");
- [ abc.length, abc.input, abc ];
- `, "1,a\naba,\na")
- })
-}
-
-func TestRegExp_compile(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var abc = /[\s\S]a/;
- abc.compile('^\w+');
- `, "undefined")
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/repl/repl.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/repl/repl.go
new file mode 100644
index 000000000..0d70cc051
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/repl/repl.go
@@ -0,0 +1,115 @@
+// Package repl implements a REPL (read-eval-print loop) for otto.
+package repl
+
+import (
+ "fmt"
+ "io"
+ "strings"
+ "sync/atomic"
+
+ "github.com/robertkrimen/otto"
+ "gopkg.in/readline.v1"
+)
+
+var counter uint32
+
+// DebuggerHandler implements otto's debugger handler signature, providing a
+// simple drop-in debugger implementation.
+func DebuggerHandler(vm *otto.Otto) {
+ i := atomic.AddUint32(&counter, 1)
+
+ // purposefully ignoring the error here - we can't do anything useful with
+ // it except panicking, and that'd be pretty rude. it'd be easy enough for a
+ // consumer to define an equivalent function that _does_ panic if desired.
+ _ = RunWithPrompt(vm, fmt.Sprintf("DEBUGGER[%d]>", i))
+}
+
+// Run creates a REPL with the default prompt and no prelude.
+func Run(vm *otto.Otto) error {
+ return RunWithPromptAndPrelude(vm, "", "")
+}
+
+// RunWithPrompt runs a REPL with the given prompt and no prelude.
+func RunWithPrompt(vm *otto.Otto, prompt string) error {
+ return RunWithPromptAndPrelude(vm, prompt, "")
+}
+
+// RunWithPrelude runs a REPL with the default prompt and the given prelude.
+func RunWithPrelude(vm *otto.Otto, prelude string) error {
+ return RunWithPromptAndPrelude(vm, "", prelude)
+}
+
+// RunWithPromptAndPrelude runs a REPL with the given prompt and prelude.
+func RunWithPromptAndPrelude(vm *otto.Otto, prompt, prelude string) error {
+ if prompt == "" {
+ prompt = ">"
+ }
+
+ prompt = strings.Trim(prompt, " ")
+ prompt += " "
+
+ rl, err := readline.New(prompt)
+ if err != nil {
+ return err
+ }
+
+ if prelude != "" {
+ if _, err := io.Copy(rl.Stderr(), strings.NewReader(prelude+"\n")); err != nil {
+ return err
+ }
+
+ rl.Refresh()
+ }
+
+ var d []string
+
+ for {
+ l, err := rl.Readline()
+ if err != nil {
+ if err == readline.ErrInterrupt {
+ if d != nil {
+ d = nil
+
+ rl.SetPrompt(prompt)
+ rl.Refresh()
+
+ continue
+ }
+
+ break
+ }
+
+ return err
+ }
+
+ if l == "" {
+ continue
+ }
+
+ d = append(d, l)
+
+ s, err := vm.Compile("repl", strings.Join(d, "\n"))
+ if err != nil {
+ rl.SetPrompt(strings.Repeat(" ", len(prompt)))
+ } else {
+ rl.SetPrompt(prompt)
+
+ d = nil
+
+ v, err := vm.Eval(s)
+ if err != nil {
+ if oerr, ok := err.(*otto.Error); ok {
+ io.Copy(rl.Stdout(), strings.NewReader(oerr.String()))
+ } else {
+ io.Copy(rl.Stdout(), strings.NewReader(err.Error()))
+ }
+ } else {
+ rl.Stdout().Write([]byte(v.String() + "\n"))
+ }
+ }
+
+ rl.Refresh()
+ }
+
+ return rl.Close()
+}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/runtime.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/runtime.go
index 1ac1b435e..168cb1cde 100644
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/runtime.go
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/runtime.go
@@ -2,6 +2,8 @@ package otto
import (
"errors"
+ "fmt"
+ "math"
"reflect"
"sync"
@@ -52,6 +54,7 @@ type _runtime struct {
scope *_scope
otto *Otto
eval *_object // The builtin eval, for determine indirect versus direct invocation
+ debugger func(*Otto)
labels []string // FIXME
lck sync.Mutex
@@ -191,6 +194,148 @@ func (self *_runtime) safeToValue(value interface{}) (Value, error) {
return result, err
}
+// convertNumeric converts numeric parameter val from js to that of type t if it is safe to do so, otherwise it panics.
+// This allows literals (int64), bitwise values (int32) and the general form (float64) of javascript numerics to be passed as parameters to go functions easily.
+func convertNumeric(val reflect.Value, t reflect.Type) reflect.Value {
+ if val.Kind() == t.Kind() {
+ return val
+ }
+
+ if val.Kind() == reflect.Interface {
+ val = reflect.ValueOf(val.Interface())
+ }
+
+ switch val.Kind() {
+ case reflect.Float32, reflect.Float64:
+ f64 := val.Float()
+ switch t.Kind() {
+ case reflect.Float64:
+ return reflect.ValueOf(f64)
+ case reflect.Float32:
+ if reflect.Zero(t).OverflowFloat(f64) {
+ panic("converting float64 to float32 would overflow")
+ }
+
+ return val.Convert(t)
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ i64 := int64(f64)
+ if float64(i64) != f64 {
+ panic(fmt.Sprintf("converting %v to %v would cause loss of precision", val.Type(), t))
+ }
+
+ // The float represents an integer
+ val = reflect.ValueOf(i64)
+ default:
+ panic(fmt.Sprintf("cannot convert %v to %v", val.Type(), t))
+ }
+ }
+
+ switch val.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ i64 := val.Int()
+ switch t.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ if reflect.Zero(t).OverflowInt(i64) {
+ panic(fmt.Sprintf("converting %v to %v would overflow", val.Type(), t))
+ }
+ return val.Convert(t)
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ if i64 < 0 {
+ panic(fmt.Sprintf("converting %v to %v would underflow", val.Type(), t))
+ }
+ if reflect.Zero(t).OverflowUint(uint64(i64)) {
+ panic(fmt.Sprintf("converting %v to %v would overflow", val.Type(), t))
+ }
+ return val.Convert(t)
+ }
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ u64 := val.Uint()
+ switch t.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ if u64 > math.MaxInt64 || reflect.Zero(t).OverflowInt(int64(u64)) {
+ panic(fmt.Sprintf("converting %v to %v would overflow", val.Type(), t))
+ }
+ return val.Convert(t)
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ if reflect.Zero(t).OverflowUint(u64) {
+ panic(fmt.Sprintf("converting %v to %v would overflow", val.Type(), t))
+ }
+ return val.Convert(t)
+ }
+ }
+
+ panic(fmt.Sprintf("unsupported type %v for numeric conversion", val.Type()))
+}
+
+// callParamConvert converts request val to type t if possible.
+// If the conversion fails due to overflow or type miss-match then it panics.
+// If no conversion is known then the original value is returned.
+func callParamConvert(val reflect.Value, t reflect.Type) reflect.Value {
+ if val.Kind() == reflect.Interface {
+ val = reflect.ValueOf(val.Interface())
+ }
+
+ switch t.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64:
+ if val.Kind() == t.Kind() {
+ // Types already match
+ return val
+ }
+ return convertNumeric(val, t)
+ case reflect.Slice:
+ if val.Kind() != reflect.Slice {
+ // Conversion from none slice type to slice not possible
+ panic(fmt.Sprintf("cannot use %v as type %v", val, t))
+ }
+ default:
+ // No supported conversion
+ return val
+ }
+
+ elemType := t.Elem()
+ switch elemType.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.Slice:
+ // Attempt to convert to slice of the type t
+ s := reflect.MakeSlice(reflect.SliceOf(elemType), val.Len(), val.Len())
+ for i := 0; i < val.Len(); i++ {
+ s.Index(i).Set(callParamConvert(val.Index(i), elemType))
+ }
+
+ return s
+ }
+
+ // Not a slice type we can convert
+ return val
+}
+
+// callSliceRequired returns true if CallSlice is required instead of Call.
+func callSliceRequired(param reflect.Type, val reflect.Value) bool {
+ vt := val.Type()
+ for param.Kind() == reflect.Slice {
+ if val.Kind() == reflect.Interface {
+ val = reflect.ValueOf(val.Interface())
+ vt = val.Type()
+ }
+
+ if vt.Kind() != reflect.Slice {
+ return false
+ }
+
+ vt = vt.Elem()
+ if val.Kind() != reflect.Invalid {
+ if val.Len() > 0 {
+ val = val.Index(0)
+ } else {
+ val = reflect.Value{}
+ }
+ }
+ param = param.Elem()
+ }
+
+ return true
+}
+
func (self *_runtime) toValue(value interface{}) Value {
switch value := value.(type) {
case Value:
@@ -217,19 +362,61 @@ func (self *_runtime) toValue(value interface{}) Value {
case reflect.Func:
// TODO Maybe cache this?
return toValue_object(self.newNativeFunction("", func(call FunctionCall) Value {
- in := make([]reflect.Value, len(call.ArgumentList))
+ argsCount := len(call.ArgumentList)
+ in := make([]reflect.Value, argsCount)
+ t := value.Type()
+ callSlice := false
+ paramsCount := t.NumIn()
+ lastParam := paramsCount - 1
+ lastArg := argsCount - 1
+ isVariadic := t.IsVariadic()
for i, value := range call.ArgumentList {
- in[i] = reflect.ValueOf(value.export())
+ var paramType reflect.Type
+ if isVariadic && i == lastArg && argsCount == paramsCount {
+ // Variadic functions last parameter and parameter numbers match incoming args
+ paramType = t.In(lastArg)
+ val := reflect.ValueOf(value.export())
+ callSlice = callSliceRequired(paramType, val)
+ if callSlice {
+ in[i] = callParamConvert(reflect.ValueOf(value.export()), paramType)
+ continue
+ }
+ }
+
+ if i >= lastParam {
+ if isVariadic {
+ paramType = t.In(lastParam).Elem()
+ } else {
+ paramType = t.In(lastParam)
+ }
+ } else {
+ paramType = t.In(i)
+ }
+ in[i] = callParamConvert(reflect.ValueOf(value.export()), paramType)
}
- out := value.Call(in)
- if len(out) == 1 {
- return self.toValue(out[0].Interface())
- } else if len(out) == 0 {
+ var out []reflect.Value
+ if callSlice {
+ out = value.CallSlice(in)
+ } else {
+ out = value.Call(in)
+ }
+
+ l := len(out)
+ switch l {
+ case 0:
return Value{}
+ case 1:
+ return self.toValue(out[0].Interface())
}
- panic(call.runtime.panicTypeError())
+ // Return an array of the values to emulate multi value return.
+ // In the future this can be used along side destructuring assignment.
+ s := make([]interface{}, l)
+ for i, v := range out {
+ s[i] = self.toValue(v.Interface())
+ }
+ return self.toValue(s)
}))
case reflect.Struct:
return toValue_object(self.newGoStructObject(value))
@@ -280,7 +467,7 @@ func (self *_runtime) parseSource(src interface{}) (*_nodeProgram, *ast.Program,
return nil, program, err
}
-func (self *_runtime) cmpl_run(src interface{}) (Value, error) {
+func (self *_runtime) cmpl_runOrEval(src interface{}, eval bool) (Value, error) {
result := Value{}
cmpl_program, program, err := self.parseSource(src)
if err != nil {
@@ -290,7 +477,7 @@ func (self *_runtime) cmpl_run(src interface{}) (Value, error) {
cmpl_program = cmpl_parse(program)
}
err = catchPanic(func() {
- result = self.cmpl_evaluate_nodeProgram(cmpl_program, false)
+ result = self.cmpl_evaluate_nodeProgram(cmpl_program, eval)
})
switch result.kind {
case valueEmpty:
@@ -301,6 +488,14 @@ func (self *_runtime) cmpl_run(src interface{}) (Value, error) {
return result, err
}
+func (self *_runtime) cmpl_run(src interface{}) (Value, error) {
+ return self.cmpl_runOrEval(src, false)
+}
+
+func (self *_runtime) cmpl_eval(src interface{}) (Value, error) {
+ return self.cmpl_runOrEval(src, true)
+}
+
func (self *_runtime) parseThrow(err error) {
if err == nil {
return
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/runtime_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/runtime_test.go
deleted file mode 100644
index 2510a0b3f..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/runtime_test.go
+++ /dev/null
@@ -1,778 +0,0 @@
-package otto
-
-import (
- "math"
- "testing"
-)
-
-// FIXME terst, Review tests
-
-func TestOperator(t *testing.T) {
- tt(t, func() {
- test, vm := test()
-
- test("xyzzy = 1")
- test("xyzzy", 1)
-
- if true {
- vm.Set("twoPlusTwo", func(FunctionCall) Value {
- return toValue(5)
- })
- test("twoPlusTwo( 1 )", 5)
-
- test("1 + twoPlusTwo( 1 )", 6)
-
- test("-1 + twoPlusTwo( 1 )", 4)
- }
-
- test("result = 4")
- test("result", 4)
-
- test("result += 1")
- test("result", 5)
-
- test("result *= 2")
- test("result", 10)
-
- test("result /= 2")
- test("result", 5)
-
- test("result = 112.51 % 3.1")
- test("result", 0.9100000000000019)
-
- test("result = 'Xyzzy'")
- test("result", "Xyzzy")
-
- test("result = 'Xyz' + 'zy'")
- test("result", "Xyzzy")
-
- test("result = \"Xyzzy\"")
- test("result", "Xyzzy")
-
- test("result = 1; result = result")
- test("result", 1)
-
- test(`
- var result64
- =
- 64
- , result10 =
- 10
- `)
- test("result64", 64)
- test("result10", 10)
-
- test(`
- result = 1;
- result += 1;
- `)
- test("result", 2)
- })
-}
-
-func TestFunction_(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- result = 2
- xyzzy = function() {
- result += 1
- }
- xyzzy()
- result;
- `, 3)
-
- test(`
- xyzzy = function() {
- return 1
- }
- result = xyzzy()
- `, 1)
-
- test(`
- xyzzy = function() {}
- result = xyzzy()
- `, "undefined")
-
- test(`
- xyzzy = function() {
- return 64
- return 1
- }
- result = xyzzy()
- `, 64)
-
- test(`
- result = 4
- xyzzy = function() {
- result = 2
- }
- xyzzy();
- result;
- `, 2)
-
- test(`
- result = 4
- xyzzy = function() {
- var result
- result = 2
- }
- xyzzy();
- result;
- `, 4)
-
- test(`
- xyzzy = function() {
- var result = 4
- return result
- }
- result = xyzzy()
- `, 4)
-
- test(`
- xyzzy = function() {
- function test() {
- var result = 1
- return result
- }
- return test() + 1
- }
- result = xyzzy() + 1
- `, 3)
-
- test(`
- xyzzy = function() {
- function test() {
- var result = 1
- return result
- }
- _xyzzy = 2
- var result = _xyzzy + test() + 1
- return result
- }
- result = xyzzy() + 1;
- [ result, _xyzzy ];
- `, "5,2")
-
- test(`
- xyzzy = function(apple) {
- return 1
- }
- result = xyzzy(1)
- `, 1)
-
- test(`
- xyzzy = function(apple) {
- return apple + 1
- }
- result = xyzzy(2)
- `, 3)
-
- test(`
- {
- result = 1
- result += 1;
- }
- `, 2)
-
- test(`
- var global = 1
- outer = function() {
- var global = 2
- var inner = function(){
- return global
- }
- return inner()
- }
- result = outer()
- `, 2)
-
- test(`
- var apple = 1
- var banana = function() {
- return apple
- }
- var cherry = function() {
- var apple = 2
- return banana()
- }
- result = cherry()
- `, 1)
-
- test(`
- function xyz() {
- };
- delete xyz;
- `, false)
-
- test(`
- var abc = function __factorial(def){
- if (def === 1) {
- return def;
- } else {
- return __factorial(def-1)*def;
- }
- };
- abc(3);
- `, 6)
- })
-}
-
-func TestDoWhile(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- limit = 4;
- result = 0;
- do {
- result = result + 1;
- limit = limit - 1;
- } while (limit);
- result;
- `, 4)
-
- test(`
- result = eval("do {abc=1; break; abc=2;} while (0);");
- [ result, abc ];
- `, "1,1")
- })
-}
-
-func TestContinueBreak(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- limit = 4
- result = 0
- while (limit) {
- limit = limit - 1
- if (limit) {
- }
- else {
- break
- }
- result = result + 1
- }
- [ result, limit ];
- `, "3,0")
-
- test(`
- limit = 4
- result = 0
- while (limit) {
- limit = limit - 1
- if (limit) {
- continue
- }
- else {
- break
- }
- result = result + 1
- }
- result;
- `, 0)
-
- test(`
- limit = 4
- result = 0
- do {
- limit = limit - 1
- if (limit) {
- continue
- }
- else {
- break
- }
- result = result + 1
- } while (limit)
- result;
- `, 0)
- })
-}
-
-func TestTryCatchError(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var abc
- try {
- 1()
- }
- catch (def) {
- abc = def
- }
- abc;
- `, "TypeError: 1 is not a function")
-
- })
-}
-
-func TestPositiveNegativeZero(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`1/0`, _Infinity)
- test(`1/-0`, -_Infinity)
- test(`
- abc = -0
- 1/abc
- `, -_Infinity)
- })
-}
-
-func TestComparison(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- undefined = 1; undefined;
- `, "undefined")
-
- test("undefined == undefined", true)
-
- test("undefined != undefined", false)
-
- test("null == null", true)
-
- test("null != null", false)
-
- test("0 == 1", false)
-
- is(negativeZero(), -0)
- is(positiveZero(), 0)
- is(math.Signbit(negativeZero()), true)
- is(positiveZero() == negativeZero(), true)
-
- test("1 == 1", true)
-
- test("'Hello, World.' == 'Goodbye, World.'", false)
-
- test("'Hello, World.' == true", false)
-
- test("'Hello, World.' == false", false)
-
- test("'Hello, World.' == 1", false)
-
- test("1 == 'Hello, World.'", false)
-
- is(parseNumber("-1"), -1)
-
- test("0+Object", "0function Object() { [native code] }")
- })
-}
-
-func TestComparisonRelational(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test("0 < 0", false)
-
- test("0 > 0", false)
-
- test("0 <= 0", true)
-
- test("0 >= 0", true)
-
- test("' 0' >= 0", true)
-
- test("'_ 0' >= 0", false)
- })
-}
-
-func TestArguments(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- xyzzy = function() {
- return arguments[0]
- }
- result = xyzzy("xyzzy");
- `, "xyzzy")
-
- test(`
- xyzzy = function() {
- arguments[0] = "abcdef"
- return arguments[0]
- }
- result = xyzzy("xyzzy");
- `, "abcdef")
-
- test(`
- xyzzy = function(apple) {
- apple = "abcdef"
- return arguments[0]
- }
- result = xyzzy("xyzzy");
- `, "abcdef")
-
- test(`
- (function(){
- return arguments
- })()
- `, "[object Arguments]")
-
- test(`
- (function(){
- return arguments.length
- })()
- `, 0)
-
- test(`
- (function(){
- return arguments.length
- })(1, 2, 4, 8, 10)
- `, 5)
- })
-}
-
-func TestObjectLiteral(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- ({});
- `, "[object Object]")
-
- test(`
- var abc = {
- xyzzy: "Nothing happens.",
- get 1e2() {
- return 3.14159;
- },
- get null() {
- return true;
- },
- get "[\n]"() {
- return "<>";
- }
- };
- [ abc["1e2"], abc.null, abc["[\n]"] ];
- `, "3.14159,true,<>")
-
- test(`
- var abc = {
- xyzzy: "Nothing happens.",
- set 1e2() {
- this[3.14159] = 100;
- return Math.random();
- },
- set null(def) {
- this.def = def;
- return Math.random();
- },
- };
- [ abc["1e2"] = Infinity, abc[3.14159], abc.null = "xyz", abc.def ];
- `, "Infinity,100,xyz,xyz")
- })
-}
-
-func TestUnaryPrefix(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var result = 0;
- [++result, result];
- `, "1,1")
-
- test(`
- result = 0;
- [--result, result];
- `, "-1,-1")
-
- test(`
- var object = { valueOf: function() { return 1; } };
- result = ++object;
- [ result, typeof result ];
- `, "2,number")
-
- test(`
- var object = { valueOf: function() { return 1; } };
- result = --object;
- [ result, typeof result ];
- `, "0,number")
- })
-}
-
-func TestUnaryPostfix(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var result = 0;
- result++;
- [ result++, result ];
- `, "1,2")
-
- test(`
- result = 0;
- result--;
- [ result--, result ];
- `, "-1,-2")
-
- test(`
- var object = { valueOf: function() { return 1; } };
- result = object++;
- [ result, typeof result ];
- `, "1,number")
-
- test(`
- var object = { valueOf: function() { return 1; } };
- result = object--
- [ result, typeof result ];
- `, "1,number")
- })
-}
-
-func TestBinaryLogicalOperation(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- abc = true
- def = false
- ghi = false
- jkl = false
- result = abc && def || ghi && jkl
- `, false)
-
- test(`
- abc = true
- def = true
- ghi = false
- jkl = false
- result = abc && def || ghi && jkl
- `, true)
-
- })
-}
-
-func TestBinaryBitwiseOperation(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- abc = 1 & 2;
- def = 1 & 3;
- ghi = 1 | 3;
- jkl = 1 ^ 2;
- mno = 1 ^ 3;
- [ abc, def, ghi, jkl, mno ];
- `, "0,1,3,3,2")
- })
-}
-
-func TestBinaryShiftOperation(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- high = (1 << 30) - 1 + (1 << 30)
- low = -high - 1
- abc = 23 << 1
- def = -105 >> 1
- ghi = 23 << 2
- jkl = 1 >>> 31
- mno = 1 << 64
- pqr = 1 >> 2
- stu = -2 >> 4
- vwx = low >> 1
- yz = low >>> 1
- `)
- test("abc", 46)
- test("def", -53)
- test("ghi", 92)
- test("jkl", 0)
- test("mno", 1)
- test("pqr", 0)
- test("stu", -1)
- test("vwx", -1073741824)
- test("yz", 1073741824)
- })
-}
-
-func TestParenthesizing(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- abc = 1 + 2 * 3
- def = (1 + 2) * 3
- ghi = !(false || true)
- jkl = !false || true
- `)
- test("abc", 7)
- test("def", 9)
- test("ghi", false)
- test("jkl", true)
- })
-}
-
-func Test_instanceof(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- abc = {} instanceof Object;
- `, true)
-
- test(`
- abc = "abc" instanceof Object;
- `, false)
-
- test(`raise:
- abc = {} instanceof "abc";
- `, "TypeError: Expecting a function in instanceof check, but got: abc")
-
- test(`raise:
- "xyzzy" instanceof Math;
- `, "TypeError")
- })
-}
-
-func TestIn(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- abc = "prototype" in Object;
- def = "xyzzy" in Object;
- [ abc, def ];
- `, "true,false")
- })
-}
-
-func Test_new(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- abc = new Boolean;
- def = new Boolean(1);
- [ abc, def ];
- `, "false,true")
- })
-}
-
-func TestNewFunction(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- new Function("return 11")()
- `, 11)
-
- test(`
- abc = 10
- new Function("abc += 1")()
- abc
- `, 11)
-
- test(`
- new Function("a", "b", "c", "return b + 2")(10, 11, 12)
- `, 13)
-
- test(`raise:
- new 1
- `, "TypeError: 1 is not a function")
-
- // TODO Better error reporting: new this
- test(`raise:
- new this
- `, "TypeError: [object environment] is not a function")
-
- test(`raise:
- new {}
- `, "TypeError: [object Object] is not a function")
- })
-}
-
-func TestNewPrototype(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- abc = { 'xyzzy': 'Nothing happens.' }
- function Xyzzy(){}
- Xyzzy.prototype = abc;
- (new Xyzzy()).xyzzy
- `, "Nothing happens.")
- })
-}
-
-func TestBlock(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var abc=0;
- var ghi;
- def: {
- do {
- abc++;
- if (!(abc < 10)) {
- break def;
- ghi = "ghi";
- }
- } while (true);
- }
- [ abc,ghi ];
- `, "10,")
- })
-}
-
-func Test_toString(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- [undefined+""]
- `, "undefined")
- })
-}
-
-func TestEvaluationOrder(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- var abc = 0;
- abc < (abc = 1) === true;
- `, true)
- })
-}
-
-func TestClone(t *testing.T) {
- tt(t, func() {
- vm1 := New()
- vm1.Run(`
- var abc = 1;
- `)
-
- vm2 := vm1.clone()
- vm1.Run(`
- abc += 2;
- `)
- vm2.Run(`
- abc += 4;
- `)
-
- is(vm1.getValue("abc"), 3)
- is(vm2.getValue("abc"), 5)
- })
-}
-
-func Test_debugger(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- debugger;
- `, "undefined")
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/script_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/script_test.go
deleted file mode 100644
index 4c35c646e..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/script_test.go
+++ /dev/null
@@ -1,78 +0,0 @@
-package otto
-
-import (
- "testing"
-)
-
-func TestScript(t *testing.T) {
- tt(t, func() {
- vm := New()
-
- script, err := vm.Compile("xyzzy", `var abc; if (!abc) abc = 0; abc += 2; abc;`)
- is(err, nil)
-
- str := script.String()
- is(str, "// xyzzy\nvar abc; if (!abc) abc = 0; abc += 2; abc;")
-
- value, err := vm.Run(script)
- is(err, nil)
- is(value, 2)
-
- if true {
- return
- }
-
- tmp, err := script.marshalBinary()
- is(err, nil)
- is(len(tmp), 1228)
-
- {
- script := &Script{}
- err = script.unmarshalBinary(tmp)
- is(err, nil)
-
- is(script.String(), str)
-
- value, err = vm.Run(script)
- is(err, nil)
- is(value, 4)
-
- tmp, err = script.marshalBinary()
- is(err, nil)
- is(len(tmp), 1228)
- }
-
- {
- script := &Script{}
- err = script.unmarshalBinary(tmp)
- is(err, nil)
-
- is(script.String(), str)
-
- value, err := vm.Run(script)
- is(err, nil)
- is(value, 6)
-
- tmp, err = script.marshalBinary()
- is(err, nil)
- is(len(tmp), 1228)
- }
-
- {
- version := scriptVersion
- scriptVersion = "bogus"
-
- script := &Script{}
- err = script.unmarshalBinary(tmp)
- is(err, "version mismatch")
-
- is(script.String(), "// \n")
- is(script.version, "")
- is(script.program == nil, true)
- is(script.filename, "")
- is(script.src, "")
-
- scriptVersion = version
- }
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/stash.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/stash.go
index 578708d3f..0d3ffa511 100644
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/stash.go
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/stash.go
@@ -273,3 +273,24 @@ func (in *_fnStash) clone(clone *_clone) _stash {
}
return out
}
+
+func getStashProperties(stash _stash) (keys []string) {
+ switch vars := stash.(type) {
+ case *_dclStash:
+ for k := range vars.property {
+ keys = append(keys, k)
+ }
+ case *_fnStash:
+ for k := range vars.property {
+ keys = append(keys, k)
+ }
+ case *_objectStash:
+ for k := range vars.object.property {
+ keys = append(keys, k)
+ }
+ default:
+ panic("unknown stash type")
+ }
+
+ return
+}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/string_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/string_test.go
deleted file mode 100644
index b7b06324b..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/string_test.go
+++ /dev/null
@@ -1,365 +0,0 @@
-package otto
-
-import (
- "testing"
-)
-
-func TestString(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- abc = (new String("xyzzy")).length;
- def = new String().length;
- ghi = new String("Nothing happens.").length;
- `)
- test("abc", 5)
- test("def", 0)
- test("ghi", 16)
- test(`"".length`, 0)
- test(`"a\uFFFFbc".length`, 4)
- test(`String(+0)`, "0")
- test(`String(-0)`, "0")
- test(`""+-0`, "0")
- test(`
- var abc = Object.getOwnPropertyDescriptor(String, "prototype");
- [ [ typeof String.prototype ],
- [ abc.writable, abc.enumerable, abc.configurable ] ];
- `, "object,false,false,false")
- })
-}
-
-func TestString_charAt(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- abc = "xyzzy".charAt(0)
- def = "xyzzy".charAt(11)
- `)
- test("abc", "x")
- test("def", "")
- })
-}
-
-func TestString_charCodeAt(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`
- abc = "xyzzy".charCodeAt(0)
- def = "xyzzy".charCodeAt(11)
- `)
- test("abc", 120)
- test("def", _NaN)
- })
-}
-
-func TestString_fromCharCode(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`String.fromCharCode()`, []uint16{})
- test(`String.fromCharCode(88, 121, 122, 122, 121)`, []uint16{88, 121, 122, 122, 121}) // FIXME terst, Double-check these...
- test(`String.fromCharCode("88", 121, 122, 122.05, 121)`, []uint16{88, 121, 122, 122, 121})
- test(`String.fromCharCode("88", 121, 122, NaN, 121)`, []uint16{88, 121, 122, 0, 121})
- test(`String.fromCharCode("0x21")`, []uint16{33})
- test(`String.fromCharCode(-1).charCodeAt(0)`, 65535)
- test(`String.fromCharCode(65535).charCodeAt(0)`, 65535)
- test(`String.fromCharCode(65534).charCodeAt(0)`, 65534)
- test(`String.fromCharCode(4294967295).charCodeAt(0)`, 65535)
- test(`String.fromCharCode(4294967294).charCodeAt(0)`, 65534)
- test(`String.fromCharCode(0x0024) === "$"`, true)
- })
-}
-
-func TestString_concat(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`"".concat()`, "")
- test(`"".concat("abc", "def")`, "abcdef")
- test(`"".concat("abc", undefined, "def")`, "abcundefineddef")
- })
-}
-
-func TestString_indexOf(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`"".indexOf("")`, 0)
- test(`"".indexOf("", 11)`, 0)
- test(`"abc".indexOf("")`, 0)
- test(`"abc".indexOf("", 11)`, 3)
- test(`"abc".indexOf("a")`, 0)
- test(`"abc".indexOf("bc")`, 1)
- test(`"abc".indexOf("bc", 11)`, -1)
- test(`"$$abcdabcd".indexOf("ab", function(){return -Infinity;}())`, 2)
- test(`"$$abcdabcd".indexOf("ab", function(){return NaN;}())`, 2)
-
- test(`
- var abc = {toString:function(){return "\u0041B";}}
- var def = {valueOf:function(){return true;}}
- var ghi = "ABB\u0041BABAB";
- var jkl;
- with(ghi) {
- jkl = indexOf(abc, def);
- }
- jkl;
- `, 3)
- })
-}
-
-func TestString_lastIndexOf(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`"".lastIndexOf("")`, 0)
- test(`"".lastIndexOf("", 11)`, 0)
- test(`"abc".lastIndexOf("")`, 3)
- test(`"abc".lastIndexOf("", 11)`, 3)
- test(`"abc".lastIndexOf("a")`, 0)
- test(`"abc".lastIndexOf("bc")`, 1)
- test(`"abc".lastIndexOf("bc", 11)`, 1)
- test(`"abc".lastIndexOf("bc", 0)`, -1)
- test(`"abc".lastIndexOf("abcabcabc", 2)`, -1)
- test(`"abc".lastIndexOf("abc", 0)`, 0)
- test(`"abc".lastIndexOf("abc", 1)`, 0)
- test(`"abc".lastIndexOf("abc", 2)`, 0)
- test(`"abc".lastIndexOf("abc", 3)`, 0)
-
- test(`
- abc = new Object(true);
- abc.lastIndexOf = String.prototype.lastIndexOf;
- abc.lastIndexOf(true, false);
- `, 0)
- })
-}
-
-func TestString_match(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`"abc____abc_abc___".match(/__abc/)`, "__abc")
- test(`"abc___abc_abc__abc__abc".match(/abc/g)`, "abc,abc,abc,abc,abc")
- test(`"abc____abc_abc___".match(/__abc/g)`, "__abc")
- test(`
- abc = /abc/g
- "abc___abc_abc__abc__abc".match(abc)
- `, "abc,abc,abc,abc,abc")
- test(`abc.lastIndex`, 23)
- })
-}
-
-func TestString_replace(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`"abc_abc".replace(/abc/, "$&123")`, "abc123_abc")
- test(`"abc_abc".replace(/abc/g, "$&123")`, "abc123_abc123")
- test(`"abc_abc_".replace(/abc/g, "$&123")`, "abc123_abc123_")
- test(`"_abc_abc_".replace(/abc/g, "$&123")`, "_abc123_abc123_")
- test(`"abc".replace(/abc/, "$&123")`, "abc123")
- test(`"abc_".replace(/abc/, "$&123")`, "abc123_")
- test("\"^abc$\".replace(/abc/, \"$`def\")", "^^def$")
- test("\"^abc$\".replace(/abc/, \"def$`\")", "^def^$")
- test(`"_abc_abd_".replace(/ab(c|d)/g, "$1")`, "_c_d_")
- test(`
- "_abc_abd_".replace(/ab(c|d)/g, function(){
- })
- `, "_undefined_undefined_")
-
- test(`"b".replace(/(a)?(b)?/, "_$1_")`, "__")
- test(`
- "b".replace(/(a)?(b)?/, function(a, b, c, d, e, f){
- return [a, b, c, d, e, f]
- })
- `, "b,,b,0,b,")
-
- test(`
- var abc = 'She sells seashells by the seashore.';
- var def = /sh/;
- [ abc.replace(def, "$'" + 'sch') ];
- `, "She sells seaells by the seashore.schells by the seashore.")
- })
-}
-
-func TestString_search(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`"abc".search(/abc/)`, 0)
- test(`"abc".search(/def/)`, -1)
- test(`"abc".search(/c$/)`, 2)
- test(`"abc".search(/$/)`, 3)
- })
-}
-
-func TestString_split(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`"abc".split("", 1)`, "a")
- test(`"abc".split("", 2)`, "a,b")
- test(`"abc".split("", 3)`, "a,b,c")
- test(`"abc".split("", 4)`, "a,b,c")
- test(`"abc".split("", 11)`, "a,b,c")
- test(`"abc".split("", 0)`, "")
- test(`"abc".split("")`, "a,b,c")
-
- test(`"abc".split(undefined)`, "abc")
-
- test(`"__1__3_1__2__".split("_")`, ",,1,,3,1,,2,,")
-
- test(`"__1__3_1__2__".split(/_/)`, ",,1,,3,1,,2,,")
-
- test(`"ab".split(/a*/)`, ",b")
-
- test(`_ = "A<B>bold</B>and<CODE>coded</CODE>".split(/<(\/)?([^<>]+)>/)`, "A,,B,bold,/,B,and,,CODE,coded,/,CODE,")
- test(`_.length`, 13)
- test(`_[1] === undefined`, true)
- test(`_[12] === ""`, true)
-
- test(`
- var abc = new String("one-1 two-2 three-3");
- var def = abc.split(new RegExp);
-
- [ def.constructor === Array, abc.length, def.length, def.join('') ];
- `, "true,19,19,one-1 two-2 three-3")
- })
-}
-
-func TestString_slice(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`"abc".slice()`, "abc")
- test(`"abc".slice(0)`, "abc")
- test(`"abc".slice(0,11)`, "abc")
- test(`"abc".slice(0,-1)`, "ab")
- test(`"abc".slice(-1,11)`, "c")
- test(`abc = "abc"; abc.slice(abc.length+1, 0)`, "")
- })
-}
-
-func TestString_substring(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`"abc".substring()`, "abc")
- test(`"abc".substring(0)`, "abc")
- test(`"abc".substring(0,11)`, "abc")
- test(`"abc".substring(11,0)`, "abc")
- test(`"abc".substring(0,-1)`, "")
- test(`"abc".substring(-1,11)`, "abc")
- test(`"abc".substring(11,1)`, "bc")
- test(`"abc".substring(1)`, "bc")
- test(`"abc".substring(Infinity, Infinity)`, "")
- })
-}
-
-func TestString_toCase(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`"abc".toLowerCase()`, "abc")
- test(`"ABC".toLowerCase()`, "abc")
- test(`"abc".toLocaleLowerCase()`, "abc")
- test(`"ABC".toLocaleLowerCase()`, "abc")
- test(`"abc".toUpperCase()`, "ABC")
- test(`"ABC".toUpperCase()`, "ABC")
- test(`"abc".toLocaleUpperCase()`, "ABC")
- test(`"ABC".toLocaleUpperCase()`, "ABC")
- })
-}
-
-func Test_floatToString(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`String(-1234567890)`, "-1234567890")
- test(`-+String(-(-1234567890))`, -1234567890)
- test(`String(-1e128)`, "-1e+128")
- test(`String(0.12345)`, "0.12345")
- test(`String(-0.00000012345)`, "-1.2345e-7")
- test(`String(0.0000012345)`, "0.0000012345")
- test(`String(1000000000000000000000)`, "1e+21")
- test(`String(1e21)`, "1e+21")
- test(`String(1E21)`, "1e+21")
- test(`String(-1000000000000000000000)`, "-1e+21")
- test(`String(-1e21)`, "-1e+21")
- test(`String(-1E21)`, "-1e+21")
- test(`String(0.0000001)`, "1e-7")
- test(`String(1e-7)`, "1e-7")
- test(`String(1E-7)`, "1e-7")
- test(`String(-0.0000001)`, "-1e-7")
- test(`String(-1e-7)`, "-1e-7")
- test(`String(-1E-7)`, "-1e-7")
- })
-}
-
-func TestString_indexing(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- // Actually a test of stringToArrayIndex, under the hood.
- test(`
- abc = new String("abc");
- index = Math.pow(2, 32);
- [ abc.length, abc[index], abc[index+1], abc[index+2], abc[index+3] ];
- `, "3,,,,")
- })
-}
-
-func TestString_trim(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`' \n abc \t \n'.trim();`, "abc")
- test(`" abc\u000B".trim()`, "abc")
- test(`"abc ".trim()`, "abc")
- test(`
- var a = "\u180Eabc \u000B "
- var b = a.trim()
- a.length + b.length
- `, 10)
- })
-}
-
-func TestString_trimLeft(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`" abc\u000B".trimLeft()`, "abc\u000B")
- test(`"abc ".trimLeft()`, "abc ")
- test(`
- var a = "\u180Eabc \u000B "
- var b = a.trimLeft()
- a.length + b.length
- `, 13)
- })
-}
-
-func TestString_trimRight(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`" abc\u000B".trimRight()`, " abc")
- test(`" abc ".trimRight()`, " abc")
- test(`
- var a = "\u180Eabc \u000B "
- var b = a.trimRight()
- a.length + b.length
- `, 11)
- })
-}
-
-func TestString_localeCompare(t *testing.T) {
- tt(t, func() {
- test, _ := test()
-
- test(`'a'.localeCompare('c');`, -1)
- test(`'c'.localeCompare('a');`, 1)
- test(`'a'.localeCompare('a');`, 0)
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/testing_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/testing_test.go
deleted file mode 100644
index bf820bc0c..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/testing_test.go
+++ /dev/null
@@ -1,135 +0,0 @@
-package otto
-
-import (
- "./terst"
- "errors"
- "strings"
- "testing"
- "time"
-)
-
-func tt(t *testing.T, arguments ...func()) {
- halt := errors.New("A test was taking too long")
- timer := time.AfterFunc(2*time.Second, func() {
- panic(halt)
- })
- defer func() {
- timer.Stop()
- }()
- terst.Terst(t, arguments...)
-}
-
-func is(arguments ...interface{}) bool {
- var got, expect interface{}
-
- switch len(arguments) {
- case 0, 1:
- return terst.Is(arguments...)
- case 2:
- got, expect = arguments[0], arguments[1]
- default:
- got, expect = arguments[0], arguments[2]
- }
-
- switch value := got.(type) {
- case Value:
- if value.value != nil {
- got = value.value
- }
- case *Error:
- if value != nil {
- got = value.Error()
- }
- if expect == nil {
- // FIXME This is weird
- expect = ""
- }
- }
-
- if len(arguments) == 2 {
- arguments[0] = got
- arguments[1] = expect
- } else {
- arguments[0] = got
- arguments[2] = expect
- }
-
- return terst.Is(arguments...)
-}
-
-func test(arguments ...interface{}) (func(string, ...interface{}) Value, *_tester) {
- tester := newTester()
- if len(arguments) > 0 {
- tester.test(arguments[0].(string))
- }
- return tester.test, tester
-}
-
-type _tester struct {
- vm *Otto
-}
-
-func newTester() *_tester {
- return &_tester{
- vm: New(),
- }
-}
-
-func (self *_tester) Get(name string) (Value, error) {
- return self.vm.Get(name)
-}
-
-func (self *_tester) Set(name string, value interface{}) Value {
- err := self.vm.Set(name, value)
- is(err, nil)
- if err != nil {
- terst.Caller().T().FailNow()
- }
- return self.vm.getValue(name)
-}
-
-func (self *_tester) Run(src interface{}) (Value, error) {
- return self.vm.Run(src)
-}
-
-func (self *_tester) test(name string, expect ...interface{}) Value {
- vm := self.vm
- raise := false
- defer func() {
- if caught := recover(); caught != nil {
- if exception, ok := caught.(*_exception); ok {
- caught = exception.eject()
- }
- if raise {
- if len(expect) > 0 {
- is(caught, expect[0])
- }
- } else {
- dbg("Panic, caught:", caught)
- panic(caught)
- }
- }
- }()
- var value Value
- var err error
- if isIdentifier(name) {
- value = vm.getValue(name)
- } else {
- source := name
- index := strings.Index(source, "raise:")
- if index == 0 {
- raise = true
- source = source[6:]
- source = strings.TrimLeft(source, " ")
- }
- value, err = vm.runtime.cmpl_run(source)
- if err != nil {
- panic(err)
- }
- }
- value = value.resolve()
- if len(expect) > 0 {
- is(value, expect[0])
- }
- return value
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/type_function.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_function.go
index a5eb7554a..8581afd39 100644
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/type_function.go
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_function.go
@@ -147,10 +147,13 @@ func (self *_object) call(this Value, argumentList []Value, eval bool, frame _fr
case _nodeFunctionObject:
rt := self.runtime
stash := rt.enterFunctionScope(fn.stash, this)
+ rt.scope.frame = _frame{
+ callee: fn.node.name,
+ file: fn.node.file,
+ }
defer func() {
rt.leaveScope()
}()
- rt.scope.frame = frame
callValue := rt.cmpl_call_nodeFunction(self, stash, fn.node, this, argumentList)
if value, valid := callValue.value.(_result); valid {
return value.value
@@ -260,3 +263,9 @@ func (self *FunctionCall) thisClassObject(class string) *_object {
func (self FunctionCall) toObject(value Value) *_object {
return self.runtime.toObject(value)
}
+
+// CallerLocation will return file location information (file:line:pos) where this function is being called.
+func (self FunctionCall) CallerLocation() string {
+ // see error.go for location()
+ return self.runtime.scope.frame.location()
+}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/type_go_map.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_go_map.go
index 542a2c29d..3e204a028 100644
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/type_go_map.go
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/type_go_map.go
@@ -60,7 +60,7 @@ func goMapEnumerate(self *_object, all bool, each func(string) bool) {
object := self.value.(*_goMapObject)
keys := object.value.MapKeys()
for _, key := range keys {
- if !each(key.String()) {
+ if !each(toValue(key).String()) {
return
}
}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore/source.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore/source.go
index 65754ab71..7c5df9714 100644
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore/source.go
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore/source.go
@@ -3456,6 +3456,7 @@ func underscore() []byte {
0x69, 0x73, 0x29, 0x3b, 0x0a,
}
}
+
// Underscore.js 1.4.4
// http://underscorejs.org
// (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_arrays_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_arrays_test.go
deleted file mode 100644
index 9d6297820..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_arrays_test.go
+++ /dev/null
@@ -1,344 +0,0 @@
-package otto
-
-import (
- "testing"
-)
-
-// first
-func Test_underscore_arrays_0(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("first", function() {
- equal(_.first([1,2,3]), 1, 'can pull out the first element of an array');
- equal(_([1, 2, 3]).first(), 1, 'can perform OO-style "first()"');
- equal(_.first([1,2,3], 0).join(', '), "", 'can pass an index to first');
- equal(_.first([1,2,3], 2).join(', '), '1, 2', 'can pass an index to first');
- equal(_.first([1,2,3], 5).join(', '), '1, 2, 3', 'can pass an index to first');
- var result = (function(){ return _.first(arguments); })(4, 3, 2, 1);
- equal(result, 4, 'works on an arguments object.');
- result = _.map([[1,2,3],[1,2,3]], _.first);
- equal(result.join(','), '1,1', 'works well with _.map');
- result = (function() { return _.take([1,2,3], 2); })();
- equal(result.join(','), '1,2', 'aliased as take');
-
- equal(_.first(null), undefined, 'handles nulls');
- });
- `)
- })
-}
-
-// rest
-func Test_underscore_arrays_1(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("rest", function() {
- var numbers = [1, 2, 3, 4];
- equal(_.rest(numbers).join(", "), "2, 3, 4", 'working rest()');
- equal(_.rest(numbers, 0).join(", "), "1, 2, 3, 4", 'working rest(0)');
- equal(_.rest(numbers, 2).join(', '), '3, 4', 'rest can take an index');
- var result = (function(){ return _(arguments).tail(); })(1, 2, 3, 4);
- equal(result.join(', '), '2, 3, 4', 'aliased as tail and works on arguments object');
- result = _.map([[1,2,3],[1,2,3]], _.rest);
- equal(_.flatten(result).join(','), '2,3,2,3', 'works well with _.map');
- result = (function(){ return _(arguments).drop(); })(1, 2, 3, 4);
- equal(result.join(', '), '2, 3, 4', 'aliased as drop and works on arguments object');
- });
- `)
- })
-}
-
-// initial
-func Test_underscore_arrays_2(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("initial", function() {
- equal(_.initial([1,2,3,4,5]).join(", "), "1, 2, 3, 4", 'working initial()');
- equal(_.initial([1,2,3,4],2).join(", "), "1, 2", 'initial can take an index');
- var result = (function(){ return _(arguments).initial(); })(1, 2, 3, 4);
- equal(result.join(", "), "1, 2, 3", 'initial works on arguments object');
- result = _.map([[1,2,3],[1,2,3]], _.initial);
- equal(_.flatten(result).join(','), '1,2,1,2', 'initial works with _.map');
- });
- `)
- })
-}
-
-// last
-func Test_underscore_arrays_3(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("last", function() {
- equal(_.last([1,2,3]), 3, 'can pull out the last element of an array');
- equal(_.last([1,2,3], 0).join(', '), "", 'can pass an index to last');
- equal(_.last([1,2,3], 2).join(', '), '2, 3', 'can pass an index to last');
- equal(_.last([1,2,3], 5).join(', '), '1, 2, 3', 'can pass an index to last');
- var result = (function(){ return _(arguments).last(); })(1, 2, 3, 4);
- equal(result, 4, 'works on an arguments object');
- result = _.map([[1,2,3],[1,2,3]], _.last);
- equal(result.join(','), '3,3', 'works well with _.map');
-
- equal(_.last(null), undefined, 'handles nulls');
- });
- `)
- })
-}
-
-// compact
-func Test_underscore_arrays_4(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("compact", function() {
- equal(_.compact([0, 1, false, 2, false, 3]).length, 3, 'can trim out all falsy values');
- var result = (function(){ return _.compact(arguments).length; })(0, 1, false, 2, false, 3);
- equal(result, 3, 'works on an arguments object');
- });
- `)
- })
-}
-
-// flatten
-func Test_underscore_arrays_5(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("flatten", function() {
- var list = [1, [2], [3, [[[4]]]]];
- deepEqual(_.flatten(list), [1,2,3,4], 'can flatten nested arrays');
- deepEqual(_.flatten(list, true), [1,2,3,[[[4]]]], 'can shallowly flatten nested arrays');
- var result = (function(){ return _.flatten(arguments); })(1, [2], [3, [[[4]]]]);
- deepEqual(result, [1,2,3,4], 'works on an arguments object');
- });
- `)
- })
-}
-
-// without
-func Test_underscore_arrays_6(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("without", function() {
- var list = [1, 2, 1, 0, 3, 1, 4];
- equal(_.without(list, 0, 1).join(', '), '2, 3, 4', 'can remove all instances of an object');
- var result = (function(){ return _.without(arguments, 0, 1); })(1, 2, 1, 0, 3, 1, 4);
- equal(result.join(', '), '2, 3, 4', 'works on an arguments object');
-
- var list = [{one : 1}, {two : 2}];
- ok(_.without(list, {one : 1}).length == 2, 'uses real object identity for comparisons.');
- ok(_.without(list, list[0]).length == 1, 'ditto.');
- });
- `)
- })
-}
-
-// uniq
-func Test_underscore_arrays_7(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("uniq", function() {
- var list = [1, 2, 1, 3, 1, 4];
- equal(_.uniq(list).join(', '), '1, 2, 3, 4', 'can find the unique values of an unsorted array');
-
- var list = [1, 1, 1, 2, 2, 3];
- equal(_.uniq(list, true).join(', '), '1, 2, 3', 'can find the unique values of a sorted array faster');
-
- var list = [{name:'moe'}, {name:'curly'}, {name:'larry'}, {name:'curly'}];
- var iterator = function(value) { return value.name; };
- equal(_.map(_.uniq(list, false, iterator), iterator).join(', '), 'moe, curly, larry', 'can find the unique values of an array using a custom iterator');
-
- equal(_.map(_.uniq(list, iterator), iterator).join(', '), 'moe, curly, larry', 'can find the unique values of an array using a custom iterator without specifying whether array is sorted');
-
- var iterator = function(value) { return value +1; };
- var list = [1, 2, 2, 3, 4, 4];
- equal(_.uniq(list, true, iterator).join(', '), '1, 2, 3, 4', 'iterator works with sorted array');
-
- var result = (function(){ return _.uniq(arguments); })(1, 2, 1, 3, 1, 4);
- equal(result.join(', '), '1, 2, 3, 4', 'works on an arguments object');
- });
- `)
- })
-}
-
-// intersection
-func Test_underscore_arrays_8(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("intersection", function() {
- var stooges = ['moe', 'curly', 'larry'], leaders = ['moe', 'groucho'];
- equal(_.intersection(stooges, leaders).join(''), 'moe', 'can take the set intersection of two arrays');
- equal(_(stooges).intersection(leaders).join(''), 'moe', 'can perform an OO-style intersection');
- var result = (function(){ return _.intersection(arguments, leaders); })('moe', 'curly', 'larry');
- equal(result.join(''), 'moe', 'works on an arguments object');
- });
- `)
- })
-}
-
-// union
-func Test_underscore_arrays_9(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("union", function() {
- var result = _.union([1, 2, 3], [2, 30, 1], [1, 40]);
- equal(result.join(' '), '1 2 3 30 40', 'takes the union of a list of arrays');
-
- var result = _.union([1, 2, 3], [2, 30, 1], [1, 40, [1]]);
- equal(result.join(' '), '1 2 3 30 40 1', 'takes the union of a list of nested arrays');
- });
- `)
- })
-}
-
-// difference
-func Test_underscore_arrays_10(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("difference", function() {
- var result = _.difference([1, 2, 3], [2, 30, 40]);
- equal(result.join(' '), '1 3', 'takes the difference of two arrays');
-
- var result = _.difference([1, 2, 3, 4], [2, 30, 40], [1, 11, 111]);
- equal(result.join(' '), '3 4', 'takes the difference of three arrays');
- });
- `)
- })
-}
-
-// zip
-func Test_underscore_arrays_11(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('zip', function() {
- var names = ['moe', 'larry', 'curly'], ages = [30, 40, 50], leaders = [true];
- var stooges = _.zip(names, ages, leaders);
- equal(String(stooges), 'moe,30,true,larry,40,,curly,50,', 'zipped together arrays of different lengths');
- });
- `)
- })
-}
-
-// object
-func Test_underscore_arrays_12(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('object', function() {
- var result = _.object(['moe', 'larry', 'curly'], [30, 40, 50]);
- var shouldBe = {moe: 30, larry: 40, curly: 50};
- ok(_.isEqual(result, shouldBe), 'two arrays zipped together into an object');
-
- result = _.object([['one', 1], ['two', 2], ['three', 3]]);
- shouldBe = {one: 1, two: 2, three: 3};
- ok(_.isEqual(result, shouldBe), 'an array of pairs zipped together into an object');
-
- var stooges = {moe: 30, larry: 40, curly: 50};
- ok(_.isEqual(_.object(_.pairs(stooges)), stooges), 'an object converted to pairs and back to an object');
-
- ok(_.isEqual(_.object(null), {}), 'handles nulls');
- });
- `)
- })
-}
-
-// indexOf
-func Test_underscore_arrays_13(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("indexOf", function() {
- var numbers = [1, 2, 3];
- numbers.indexOf = null;
- equal(_.indexOf(numbers, 2), 1, 'can compute indexOf, even without the native function');
- var result = (function(){ return _.indexOf(arguments, 2); })(1, 2, 3);
- equal(result, 1, 'works on an arguments object');
- equal(_.indexOf(null, 2), -1, 'handles nulls properly');
-
- var numbers = [10, 20, 30, 40, 50], num = 35;
- var index = _.indexOf(numbers, num, true);
- equal(index, -1, '35 is not in the list');
-
- numbers = [10, 20, 30, 40, 50]; num = 40;
- index = _.indexOf(numbers, num, true);
- equal(index, 3, '40 is in the list');
-
- numbers = [1, 40, 40, 40, 40, 40, 40, 40, 50, 60, 70]; num = 40;
- index = _.indexOf(numbers, num, true);
- equal(index, 1, '40 is in the list');
-
- numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3];
- index = _.indexOf(numbers, 2, 5);
- equal(index, 7, 'supports the fromIndex argument');
- });
- `)
- })
-}
-
-// lastIndexOf
-func Test_underscore_arrays_14(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("lastIndexOf", function() {
- var numbers = [1, 0, 1];
- equal(_.lastIndexOf(numbers, 1), 2);
-
- numbers = [1, 0, 1, 0, 0, 1, 0, 0, 0];
- numbers.lastIndexOf = null;
- equal(_.lastIndexOf(numbers, 1), 5, 'can compute lastIndexOf, even without the native function');
- equal(_.lastIndexOf(numbers, 0), 8, 'lastIndexOf the other element');
- var result = (function(){ return _.lastIndexOf(arguments, 1); })(1, 0, 1, 0, 0, 1, 0, 0, 0);
- equal(result, 5, 'works on an arguments object');
- equal(_.indexOf(null, 2), -1, 'handles nulls properly');
-
- numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3];
- var index = _.lastIndexOf(numbers, 2, 2);
- equal(index, 1, 'supports the fromIndex argument');
- });
- `)
- })
-}
-
-// range
-func Test_underscore_arrays_15(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("range", function() {
- equal(_.range(0).join(''), '', 'range with 0 as a first argument generates an empty array');
- equal(_.range(4).join(' '), '0 1 2 3', 'range with a single positive argument generates an array of elements 0,1,2,...,n-1');
- equal(_.range(5, 8).join(' '), '5 6 7', 'range with two arguments a &amp; b, a&lt;b generates an array of elements a,a+1,a+2,...,b-2,b-1');
- equal(_.range(8, 5).join(''), '', 'range with two arguments a &amp; b, b&lt;a generates an empty array');
- equal(_.range(3, 10, 3).join(' '), '3 6 9', 'range with three arguments a &amp; b &amp; c, c &lt; b-a, a &lt; b generates an array of elements a,a+c,a+2c,...,b - (multiplier of a) &lt; c');
- equal(_.range(3, 10, 15).join(''), '3', 'range with three arguments a &amp; b &amp; c, c &gt; b-a, a &lt; b generates an array with a single element, equal to a');
- equal(_.range(12, 7, -2).join(' '), '12 10 8', 'range with three arguments a &amp; b &amp; c, a &gt; b, c &lt; 0 generates an array of elements a,a-c,a-2c and ends with the number not less than b');
- equal(_.range(0, -10, -1).join(' '), '0 -1 -2 -3 -4 -5 -6 -7 -8 -9', 'final example in the Python docs');
- });
- `)
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_chaining_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_chaining_test.go
deleted file mode 100644
index accf04fdc..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_chaining_test.go
+++ /dev/null
@@ -1,95 +0,0 @@
-package otto
-
-import (
- "testing"
-)
-
-// map/flatten/reduce
-func Test_underscore_chaining_0(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("map/flatten/reduce", function() {
- var lyrics = [
- "I'm a lumberjack and I'm okay",
- "I sleep all night and I work all day",
- "He's a lumberjack and he's okay",
- "He sleeps all night and he works all day"
- ];
- var counts = _(lyrics).chain()
- .map(function(line) { return line.split(''); })
- .flatten()
- .reduce(function(hash, l) {
- hash[l] = hash[l] || 0;
- hash[l]++;
- return hash;
- }, {}).value();
- ok(counts['a'] == 16 && counts['e'] == 10, 'counted all the letters in the song');
- });
- `)
- })
-}
-
-// select/reject/sortBy
-func Test_underscore_chaining_1(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("select/reject/sortBy", function() {
- var numbers = [1,2,3,4,5,6,7,8,9,10];
- numbers = _(numbers).chain().select(function(n) {
- return n % 2 == 0;
- }).reject(function(n) {
- return n % 4 == 0;
- }).sortBy(function(n) {
- return -n;
- }).value();
- equal(numbers.join(', '), "10, 6, 2", "filtered and reversed the numbers");
- });
- `)
- })
-}
-
-// select/reject/sortBy in functional style
-func Test_underscore_chaining_2(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("select/reject/sortBy in functional style", function() {
- var numbers = [1,2,3,4,5,6,7,8,9,10];
- numbers = _.chain(numbers).select(function(n) {
- return n % 2 == 0;
- }).reject(function(n) {
- return n % 4 == 0;
- }).sortBy(function(n) {
- return -n;
- }).value();
- equal(numbers.join(', '), "10, 6, 2", "filtered and reversed the numbers");
- });
- `)
- })
-}
-
-// reverse/concat/unshift/pop/map
-func Test_underscore_chaining_3(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("reverse/concat/unshift/pop/map", function() {
- var numbers = [1,2,3,4,5];
- numbers = _(numbers).chain()
- .reverse()
- .concat([5, 5, 5])
- .unshift(17)
- .pop()
- .map(function(n){ return n * 2; })
- .value();
- equal(numbers.join(', '), "34, 10, 8, 6, 4, 2, 10, 10", 'can chain together array functions.');
- });
- `)
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_collections_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_collections_test.go
deleted file mode 100644
index 9afc2a2b2..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_collections_test.go
+++ /dev/null
@@ -1,698 +0,0 @@
-package otto
-
-import (
- "testing"
-)
-
-// each
-func Test_underscore_collections_0(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("each", function() {
- _.each([1, 2, 3], function(num, i) {
- equal(num, i + 1, 'each iterators provide value and iteration count');
- });
-
- var answers = [];
- _.each([1, 2, 3], function(num){ answers.push(num * this.multiplier);}, {multiplier : 5});
- equal(answers.join(', '), '5, 10, 15', 'context object property accessed');
-
- answers = [];
- _.forEach([1, 2, 3], function(num){ answers.push(num); });
- equal(answers.join(', '), '1, 2, 3', 'aliased as "forEach"');
-
- answers = [];
- var obj = {one : 1, two : 2, three : 3};
- obj.constructor.prototype.four = 4;
- _.each(obj, function(value, key){ answers.push(key); });
- equal(answers.join(", "), 'one, two, three', 'iterating over objects works, and ignores the object prototype.');
- delete obj.constructor.prototype.four;
-
- var answer = null;
- _.each([1, 2, 3], function(num, index, arr){ if (_.include(arr, num)) answer = true; });
- ok(answer, 'can reference the original collection from inside the iterator');
-
- answers = 0;
- _.each(null, function(){ ++answers; });
- equal(answers, 0, 'handles a null properly');
- });
- `)
- })
-}
-
-// map
-func Test_underscore_collections_1(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('map', function() {
- var doubled = _.map([1, 2, 3], function(num){ return num * 2; });
- equal(doubled.join(', '), '2, 4, 6', 'doubled numbers');
-
- doubled = _.collect([1, 2, 3], function(num){ return num * 2; });
- equal(doubled.join(', '), '2, 4, 6', 'aliased as "collect"');
-
- var tripled = _.map([1, 2, 3], function(num){ return num * this.multiplier; }, {multiplier : 3});
- equal(tripled.join(', '), '3, 6, 9', 'tripled numbers with context');
-
- var doubled = _([1, 2, 3]).map(function(num){ return num * 2; });
- equal(doubled.join(', '), '2, 4, 6', 'OO-style doubled numbers');
-
- // TEST: ReferenceError: document is not defined
- return;
-
- if (document.querySelectorAll) {
- var ids = _.map(document.querySelectorAll('#map-test *'), function(n){ return n.id; });
- deepEqual(ids, ['id1', 'id2'], 'Can use collection methods on NodeLists.');
- }
-
- var ids = _.map($('#map-test').children(), function(n){ return n.id; });
- deepEqual(ids, ['id1', 'id2'], 'Can use collection methods on jQuery Array-likes.');
-
- var ids = _.map(document.images, function(n){ return n.id; });
- ok(ids[0] == 'chart_image', 'can use collection methods on HTMLCollections');
-
- var ifnull = _.map(null, function(){});
- ok(_.isArray(ifnull) && ifnull.length === 0, 'handles a null properly');
- });
- `)
- })
-}
-
-// reduce
-func Test_underscore_collections_2(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('reduce', function() {
- var sum = _.reduce([1, 2, 3], function(sum, num){ return sum + num; }, 0);
- equal(sum, 6, 'can sum up an array');
-
- var context = {multiplier : 3};
- sum = _.reduce([1, 2, 3], function(sum, num){ return sum + num * this.multiplier; }, 0, context);
- equal(sum, 18, 'can reduce with a context object');
-
- sum = _.inject([1, 2, 3], function(sum, num){ return sum + num; }, 0);
- equal(sum, 6, 'aliased as "inject"');
-
- sum = _([1, 2, 3]).reduce(function(sum, num){ return sum + num; }, 0);
- equal(sum, 6, 'OO-style reduce');
-
- var sum = _.reduce([1, 2, 3], function(sum, num){ return sum + num; });
- equal(sum, 6, 'default initial value');
-
- var ifnull;
- try {
- _.reduce(null, function(){});
- } catch (ex) {
- ifnull = ex;
- }
- ok(ifnull instanceof TypeError, 'handles a null (without inital value) properly');
-
- ok(_.reduce(null, function(){}, 138) === 138, 'handles a null (with initial value) properly');
- equal(_.reduce([], function(){}, undefined), undefined, 'undefined can be passed as a special case');
- raises(function() { _.reduce([], function(){}); }, TypeError, 'throws an error for empty arrays with no initial value');
- });
- `)
- })
-}
-
-// reduceRight
-func Test_underscore_collections_3(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('reduceRight', function() {
- var list = _.reduceRight(["foo", "bar", "baz"], function(memo, str){ return memo + str; }, '');
- equal(list, 'bazbarfoo', 'can perform right folds');
-
- var list = _.foldr(["foo", "bar", "baz"], function(memo, str){ return memo + str; }, '');
- equal(list, 'bazbarfoo', 'aliased as "foldr"');
-
- var list = _.foldr(["foo", "bar", "baz"], function(memo, str){ return memo + str; });
- equal(list, 'bazbarfoo', 'default initial value');
-
- var ifnull;
- try {
- _.reduceRight(null, function(){});
- } catch (ex) {
- ifnull = ex;
- }
- ok(ifnull instanceof TypeError, 'handles a null (without inital value) properly');
-
- var sum = _.reduceRight({a: 1, b: 2, c: 3}, function(sum, num){ return sum + num; });
- equal(sum, 6, 'default initial value on object');
-
- ok(_.reduceRight(null, function(){}, 138) === 138, 'handles a null (with initial value) properly');
-
- equal(_.reduceRight([], function(){}, undefined), undefined, 'undefined can be passed as a special case');
- raises(function() { _.reduceRight([], function(){}); }, TypeError, 'throws an error for empty arrays with no initial value');
-
- // Assert that the correct arguments are being passed.
-
- var args,
- memo = {},
- object = {a: 1, b: 2},
- lastKey = _.keys(object).pop();
-
- var expected = lastKey == 'a'
- ? [memo, 1, 'a', object]
- : [memo, 2, 'b', object];
-
- _.reduceRight(object, function() {
- args || (args = _.toArray(arguments));
- }, memo);
-
- deepEqual(args, expected);
-
- // And again, with numeric keys.
-
- object = {'2': 'a', '1': 'b'};
- lastKey = _.keys(object).pop();
- args = null;
-
- expected = lastKey == '2'
- ? [memo, 'a', '2', object]
- : [memo, 'b', '1', object];
-
- _.reduceRight(object, function() {
- args || (args = _.toArray(arguments));
- }, memo);
-
- deepEqual(args, expected);
- });
- `)
- })
-}
-
-// find
-func Test_underscore_collections_4(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('find', function() {
- var array = [1, 2, 3, 4];
- strictEqual(_.find(array, function(n) { return n > 2; }), 3, 'should return first found <value>');
- strictEqual(_.find(array, function() { return false; }), void 0, 'should return <undefined> if <value> is not found');
- });
- `)
- })
-}
-
-// detect
-func Test_underscore_collections_5(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('detect', function() {
- var result = _.detect([1, 2, 3], function(num){ return num * 2 == 4; });
- equal(result, 2, 'found the first "2" and broke the loop');
- });
- `)
- })
-}
-
-// select
-func Test_underscore_collections_6(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('select', function() {
- var evens = _.select([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
- equal(evens.join(', '), '2, 4, 6', 'selected each even number');
-
- evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
- equal(evens.join(', '), '2, 4, 6', 'aliased as "filter"');
- });
- `)
- })
-}
-
-// reject
-func Test_underscore_collections_7(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('reject', function() {
- var odds = _.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
- equal(odds.join(', '), '1, 3, 5', 'rejected each even number');
-
- var context = "obj";
-
- var evens = _.reject([1, 2, 3, 4, 5, 6], function(num){
- equal(context, "obj");
- return num % 2 != 0;
- }, context);
- equal(evens.join(', '), '2, 4, 6', 'rejected each odd number');
- });
- `)
- })
-}
-
-// all
-func Test_underscore_collections_8(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('all', function() {
- ok(_.all([], _.identity), 'the empty set');
- ok(_.all([true, true, true], _.identity), 'all true values');
- ok(!_.all([true, false, true], _.identity), 'one false value');
- ok(_.all([0, 10, 28], function(num){ return num % 2 == 0; }), 'even numbers');
- ok(!_.all([0, 11, 28], function(num){ return num % 2 == 0; }), 'an odd number');
- ok(_.all([1], _.identity) === true, 'cast to boolean - true');
- ok(_.all([0], _.identity) === false, 'cast to boolean - false');
- ok(_.every([true, true, true], _.identity), 'aliased as "every"');
- ok(!_.all([undefined, undefined, undefined], _.identity), 'works with arrays of undefined');
- });
- `)
- })
-}
-
-// any
-func Test_underscore_collections_9(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('any', function() {
- var nativeSome = Array.prototype.some;
- Array.prototype.some = null;
- ok(!_.any([]), 'the empty set');
- ok(!_.any([false, false, false]), 'all false values');
- ok(_.any([false, false, true]), 'one true value');
- ok(_.any([null, 0, 'yes', false]), 'a string');
- ok(!_.any([null, 0, '', false]), 'falsy values');
- ok(!_.any([1, 11, 29], function(num){ return num % 2 == 0; }), 'all odd numbers');
- ok(_.any([1, 10, 29], function(num){ return num % 2 == 0; }), 'an even number');
- ok(_.any([1], _.identity) === true, 'cast to boolean - true');
- ok(_.any([0], _.identity) === false, 'cast to boolean - false');
- ok(_.some([false, false, true]), 'aliased as "some"');
- Array.prototype.some = nativeSome;
- });
- `)
- })
-}
-
-// include
-func Test_underscore_collections_10(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('include', function() {
- ok(_.include([1,2,3], 2), 'two is in the array');
- ok(!_.include([1,3,9], 2), 'two is not in the array');
- ok(_.contains({moe:1, larry:3, curly:9}, 3) === true, '_.include on objects checks their values');
- ok(_([1,2,3]).include(2), 'OO-style include');
- });
- `)
- })
-}
-
-// invoke
-func Test_underscore_collections_11(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('invoke', function() {
- var list = [[5, 1, 7], [3, 2, 1]];
- var result = _.invoke(list, 'sort');
- equal(result[0].join(', '), '1, 5, 7', 'first array sorted');
- equal(result[1].join(', '), '1, 2, 3', 'second array sorted');
- });
- `)
- })
-}
-
-// invoke w/ function reference
-func Test_underscore_collections_12(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('invoke w/ function reference', function() {
- var list = [[5, 1, 7], [3, 2, 1]];
- var result = _.invoke(list, Array.prototype.sort);
- equal(result[0].join(', '), '1, 5, 7', 'first array sorted');
- equal(result[1].join(', '), '1, 2, 3', 'second array sorted');
- });
- `)
- })
-}
-
-// invoke when strings have a call method
-func Test_underscore_collections_13(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('invoke when strings have a call method', function() {
- String.prototype.call = function() {
- return 42;
- };
- var list = [[5, 1, 7], [3, 2, 1]];
- var s = "foo";
- equal(s.call(), 42, "call function exists");
- var result = _.invoke(list, 'sort');
- equal(result[0].join(', '), '1, 5, 7', 'first array sorted');
- equal(result[1].join(', '), '1, 2, 3', 'second array sorted');
- delete String.prototype.call;
- equal(s.call, undefined, "call function removed");
- });
- `)
- })
-}
-
-// pluck
-func Test_underscore_collections_14(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('pluck', function() {
- var people = [{name : 'moe', age : 30}, {name : 'curly', age : 50}];
- equal(_.pluck(people, 'name').join(', '), 'moe, curly', 'pulls names out of objects');
- });
- `)
- })
-}
-
-// where
-func Test_underscore_collections_15(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('where', function() {
- var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}];
- var result = _.where(list, {a: 1});
- equal(result.length, 3);
- equal(result[result.length - 1].b, 4);
- result = _.where(list, {b: 2});
- equal(result.length, 2);
- equal(result[0].a, 1);
- });
- `)
- })
-}
-
-// findWhere
-func Test_underscore_collections_16(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('findWhere', function() {
- var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}, {a: 2, b: 4}];
- var result = _.findWhere(list, {a: 1});
- deepEqual(result, {a: 1, b: 2});
- result = _.findWhere(list, {b: 4});
- deepEqual(result, {a: 1, b: 4});
- });
- `)
- })
-}
-
-// max
-func Test_underscore_collections_17(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('max', function() {
- equal(3, _.max([1, 2, 3]), 'can perform a regular Math.max');
-
- var neg = _.max([1, 2, 3], function(num){ return -num; });
- equal(neg, 1, 'can perform a computation-based max');
-
- equal(-Infinity, _.max({}), 'Maximum value of an empty object');
- equal(-Infinity, _.max([]), 'Maximum value of an empty array');
- equal(_.max({'a': 'a'}), -Infinity, 'Maximum value of a non-numeric collection');
-
- // TEST: Takes too long
- return;
-
- equal(299999, _.max(_.range(1,300000)), "Maximum value of a too-big array");
- });
- `)
- })
-}
-
-// min
-func Test_underscore_collections_18(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('min', function() {
- equal(1, _.min([1, 2, 3]), 'can perform a regular Math.min');
-
- var neg = _.min([1, 2, 3], function(num){ return -num; });
- equal(neg, 3, 'can perform a computation-based min');
-
- equal(Infinity, _.min({}), 'Minimum value of an empty object');
- equal(Infinity, _.min([]), 'Minimum value of an empty array');
- equal(_.min({'a': 'a'}), Infinity, 'Minimum value of a non-numeric collection');
-
- var now = new Date(9999999999);
- var then = new Date(0);
- equal(_.min([now, then]), then);
-
- // TEST: Takes too long
- return;
-
- equal(1, _.min(_.range(1,300000)), "Minimum value of a too-big array");
- });
- `)
- })
-}
-
-// sortBy
-func Test_underscore_collections_19(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('sortBy', function() {
- var people = [{name : 'curly', age : 50}, {name : 'moe', age : 30}];
- people = _.sortBy(people, function(person){ return person.age; });
- equal(_.pluck(people, 'name').join(', '), 'moe, curly', 'stooges sorted by age');
-
- var list = [undefined, 4, 1, undefined, 3, 2];
- equal(_.sortBy(list, _.identity).join(','), '1,2,3,4,,', 'sortBy with undefined values');
-
- var list = ["one", "two", "three", "four", "five"];
- var sorted = _.sortBy(list, 'length');
- equal(sorted.join(' '), 'one two four five three', 'sorted by length');
-
- function Pair(x, y) {
- this.x = x;
- this.y = y;
- }
-
- var collection = [
- new Pair(1, 1), new Pair(1, 2),
- new Pair(1, 3), new Pair(1, 4),
- new Pair(1, 5), new Pair(1, 6),
- new Pair(2, 1), new Pair(2, 2),
- new Pair(2, 3), new Pair(2, 4),
- new Pair(2, 5), new Pair(2, 6),
- new Pair(undefined, 1), new Pair(undefined, 2),
- new Pair(undefined, 3), new Pair(undefined, 4),
- new Pair(undefined, 5), new Pair(undefined, 6)
- ];
-
- var actual = _.sortBy(collection, function(pair) {
- return pair.x;
- });
-
- deepEqual(actual, collection, 'sortBy should be stable');
- });
- `)
- })
-}
-
-// groupBy
-func Test_underscore_collections_20(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('groupBy', function() {
- var parity = _.groupBy([1, 2, 3, 4, 5, 6], function(num){ return num % 2; });
- ok('0' in parity && '1' in parity, 'created a group for each value');
- equal(parity[0].join(', '), '2, 4, 6', 'put each even number in the right group');
-
- var list = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"];
- var grouped = _.groupBy(list, 'length');
- equal(grouped['3'].join(' '), 'one two six ten');
- equal(grouped['4'].join(' '), 'four five nine');
- equal(grouped['5'].join(' '), 'three seven eight');
-
- var context = {};
- _.groupBy([{}], function(){ ok(this === context); }, context);
-
- grouped = _.groupBy([4.2, 6.1, 6.4], function(num) {
- return Math.floor(num) > 4 ? 'hasOwnProperty' : 'constructor';
- });
- equal(grouped.constructor.length, 1);
- equal(grouped.hasOwnProperty.length, 2);
-
- var array = [{}];
- _.groupBy(array, function(value, index, obj){ ok(obj === array); });
-
- var array = [1, 2, 1, 2, 3];
- var grouped = _.groupBy(array);
- equal(grouped['1'].length, 2);
- equal(grouped['3'].length, 1);
- });
- `)
- })
-}
-
-// countBy
-func Test_underscore_collections_21(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('countBy', function() {
- var parity = _.countBy([1, 2, 3, 4, 5], function(num){ return num % 2 == 0; });
- equal(parity['true'], 2);
- equal(parity['false'], 3);
-
- var list = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"];
- var grouped = _.countBy(list, 'length');
- equal(grouped['3'], 4);
- equal(grouped['4'], 3);
- equal(grouped['5'], 3);
-
- var context = {};
- _.countBy([{}], function(){ ok(this === context); }, context);
-
- grouped = _.countBy([4.2, 6.1, 6.4], function(num) {
- return Math.floor(num) > 4 ? 'hasOwnProperty' : 'constructor';
- });
- equal(grouped.constructor, 1);
- equal(grouped.hasOwnProperty, 2);
-
- var array = [{}];
- _.countBy(array, function(value, index, obj){ ok(obj === array); });
-
- var array = [1, 2, 1, 2, 3];
- var grouped = _.countBy(array);
- equal(grouped['1'], 2);
- equal(grouped['3'], 1);
- });
- `)
- })
-}
-
-// sortedIndex
-func Test_underscore_collections_22(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('sortedIndex', function() {
- var numbers = [10, 20, 30, 40, 50], num = 35;
- var indexForNum = _.sortedIndex(numbers, num);
- equal(indexForNum, 3, '35 should be inserted at index 3');
-
- var indexFor30 = _.sortedIndex(numbers, 30);
- equal(indexFor30, 2, '30 should be inserted at index 2');
-
- var objects = [{x: 10}, {x: 20}, {x: 30}, {x: 40}];
- var iterator = function(obj){ return obj.x; };
- strictEqual(_.sortedIndex(objects, {x: 25}, iterator), 2);
- strictEqual(_.sortedIndex(objects, {x: 35}, 'x'), 3);
-
- var context = {1: 2, 2: 3, 3: 4};
- iterator = function(obj){ return this[obj]; };
- strictEqual(_.sortedIndex([1, 3], 2, iterator, context), 1);
- });
- `)
- })
-}
-
-// shuffle
-func Test_underscore_collections_23(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('shuffle', function() {
- var numbers = _.range(10);
- var shuffled = _.shuffle(numbers).sort();
- notStrictEqual(numbers, shuffled, 'original object is unmodified');
- equal(shuffled.join(','), numbers.join(','), 'contains the same members before and after shuffle');
- });
- `)
- })
-}
-
-// toArray
-func Test_underscore_collections_24(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('toArray', function() {
- ok(!_.isArray(arguments), 'arguments object is not an array');
- ok(_.isArray(_.toArray(arguments)), 'arguments object converted into array');
- var a = [1,2,3];
- ok(_.toArray(a) !== a, 'array is cloned');
- equal(_.toArray(a).join(', '), '1, 2, 3', 'cloned array contains same elements');
-
- var numbers = _.toArray({one : 1, two : 2, three : 3});
- equal(numbers.join(', '), '1, 2, 3', 'object flattened into array');
-
- // TEST: ReferenceError: document is not defined
- return;
-
- // test in IE < 9
- try {
- var actual = _.toArray(document.childNodes);
- } catch(ex) { }
-
- ok(_.isArray(actual), 'should not throw converting a node list');
- });
- `)
- })
-}
-
-// size
-func Test_underscore_collections_25(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('size', function() {
- equal(_.size({one : 1, two : 2, three : 3}), 3, 'can compute the size of an object');
- equal(_.size([1, 2, 3]), 3, 'can compute the size of an array');
-
- var func = function() {
- return _.size(arguments);
- };
-
- equal(func(1, 2, 3, 4), 4, 'can test the size of the arguments object');
-
- equal(_.size('hello'), 5, 'can compute the size of a string');
-
- equal(_.size(null), 0, 'handles nulls');
- });
- `)
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_functions_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_functions_test.go
deleted file mode 100644
index be59e16b3..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_functions_test.go
+++ /dev/null
@@ -1,208 +0,0 @@
-package otto
-
-import (
- "testing"
-)
-
-// bind
-func Test_underscore_functions_0(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("bind", function() {
- var context = {name : 'moe'};
- var func = function(arg) { return "name: " + (this.name || arg); };
- var bound = _.bind(func, context);
- equal(bound(), 'name: moe', 'can bind a function to a context');
-
- bound = _(func).bind(context);
- equal(bound(), 'name: moe', 'can do OO-style binding');
-
- bound = _.bind(func, null, 'curly');
- equal(bound(), 'name: curly', 'can bind without specifying a context');
-
- func = function(salutation, name) { return salutation + ': ' + name; };
- func = _.bind(func, this, 'hello');
- equal(func('moe'), 'hello: moe', 'the function was partially applied in advance');
-
- func = _.bind(func, this, 'curly');
- equal(func(), 'hello: curly', 'the function was completely applied in advance');
-
- func = function(salutation, firstname, lastname) { return salutation + ': ' + firstname + ' ' + lastname; };
- func = _.bind(func, this, 'hello', 'moe', 'curly');
- equal(func(), 'hello: moe curly', 'the function was partially applied in advance and can accept multiple arguments');
-
- func = function(context, message) { equal(this, context, message); };
- _.bind(func, 0, 0, 'can bind a function to <0>')();
- _.bind(func, '', '', 'can bind a function to an empty string')();
- _.bind(func, false, false, 'can bind a function to <false>')();
-
- // These tests are only meaningful when using a browser without a native bind function
- // To test this with a modern browser, set underscore's nativeBind to undefined
- var F = function () { return this; };
- var Boundf = _.bind(F, {hello: "moe curly"});
- equal(Boundf().hello, "moe curly", "When called without the new operator, it's OK to be bound to the context");
- });
- `)
- })
-}
-
-// partial
-func Test_underscore_functions_1(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("partial", function() {
- var obj = {name: 'moe'};
- var func = function() { return this.name + ' ' + _.toArray(arguments).join(' '); };
-
- obj.func = _.partial(func, 'a', 'b');
- equal(obj.func('c', 'd'), 'moe a b c d', 'can partially apply');
- });
- `)
- })
-}
-
-// bindAll
-func Test_underscore_functions_2(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("bindAll", function() {
- var curly = {name : 'curly'}, moe = {
- name : 'moe',
- getName : function() { return 'name: ' + this.name; },
- sayHi : function() { return 'hi: ' + this.name; }
- };
- curly.getName = moe.getName;
- _.bindAll(moe, 'getName', 'sayHi');
- curly.sayHi = moe.sayHi;
- equal(curly.getName(), 'name: curly', 'unbound function is bound to current object');
- equal(curly.sayHi(), 'hi: moe', 'bound function is still bound to original object');
-
- curly = {name : 'curly'};
- moe = {
- name : 'moe',
- getName : function() { return 'name: ' + this.name; },
- sayHi : function() { return 'hi: ' + this.name; }
- };
- _.bindAll(moe);
- curly.sayHi = moe.sayHi;
- equal(curly.sayHi(), 'hi: moe', 'calling bindAll with no arguments binds all functions to the object');
- });
- `)
- })
-}
-
-// memoize
-func Test_underscore_functions_3(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("memoize", function() {
- var fib = function(n) {
- return n < 2 ? n : fib(n - 1) + fib(n - 2);
- };
- var fastFib = _.memoize(fib);
- equal(fib(10), 55, 'a memoized version of fibonacci produces identical results');
- equal(fastFib(10), 55, 'a memoized version of fibonacci produces identical results');
-
- var o = function(str) {
- return str;
- };
- var fastO = _.memoize(o);
- equal(o('toString'), 'toString', 'checks hasOwnProperty');
- equal(fastO('toString'), 'toString', 'checks hasOwnProperty');
- });
- `)
- })
-}
-
-// once
-func Test_underscore_functions_4(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("once", function() {
- var num = 0;
- var increment = _.once(function(){ num++; });
- increment();
- increment();
- equal(num, 1);
- });
- `)
- })
-}
-
-// wrap
-func Test_underscore_functions_5(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("wrap", function() {
- var greet = function(name){ return "hi: " + name; };
- var backwards = _.wrap(greet, function(func, name){ return func(name) + ' ' + name.split('').reverse().join(''); });
- equal(backwards('moe'), 'hi: moe eom', 'wrapped the saluation function');
-
- var inner = function(){ return "Hello "; };
- var obj = {name : "Moe"};
- obj.hi = _.wrap(inner, function(fn){ return fn() + this.name; });
- equal(obj.hi(), "Hello Moe");
-
- var noop = function(){};
- var wrapped = _.wrap(noop, function(fn){ return Array.prototype.slice.call(arguments, 0); });
- var ret = wrapped(['whats', 'your'], 'vector', 'victor');
- deepEqual(ret, [noop, ['whats', 'your'], 'vector', 'victor']);
- });
- `)
- })
-}
-
-// compose
-func Test_underscore_functions_6(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("compose", function() {
- var greet = function(name){ return "hi: " + name; };
- var exclaim = function(sentence){ return sentence + '!'; };
- var composed = _.compose(exclaim, greet);
- equal(composed('moe'), 'hi: moe!', 'can compose a function that takes another');
-
- composed = _.compose(greet, exclaim);
- equal(composed('moe'), 'hi: moe!', 'in this case, the functions are also commutative');
- });
- `)
- })
-}
-
-// after
-func Test_underscore_functions_7(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("after", function() {
- var testAfter = function(afterAmount, timesCalled) {
- var afterCalled = 0;
- var after = _.after(afterAmount, function() {
- afterCalled++;
- });
- while (timesCalled--) after();
- return afterCalled;
- };
-
- equal(testAfter(5, 5), 1, "after(N) should fire after being called N times");
- equal(testAfter(5, 4), 0, "after(N) should not fire unless called N times");
- equal(testAfter(0, 0), 1, "after(0) should fire immediately");
- });
- `)
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_objects_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_objects_test.go
deleted file mode 100644
index 1973af8dd..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_objects_test.go
+++ /dev/null
@@ -1,826 +0,0 @@
-package otto
-
-import (
- "testing"
-)
-
-// keys
-func Test_underscore_objects_0(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("keys", function() {
- equal(_.keys({one : 1, two : 2}).join(', '), 'one, two', 'can extract the keys from an object');
- // the test above is not safe because it relies on for-in enumeration order
- var a = []; a[1] = 0;
- equal(_.keys(a).join(', '), '1', 'is not fooled by sparse arrays; see issue #95');
- raises(function() { _.keys(null); }, TypeError, 'throws an error for <null> values');
- raises(function() { _.keys(void 0); }, TypeError, 'throws an error for <undefined> values');
- raises(function() { _.keys(1); }, TypeError, 'throws an error for number primitives');
- raises(function() { _.keys('a'); }, TypeError, 'throws an error for string primitives');
- raises(function() { _.keys(true); }, TypeError, 'throws an error for boolean primitives');
- });
- `)
- })
-}
-
-// values
-func Test_underscore_objects_1(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("values", function() {
- equal(_.values({one: 1, two: 2}).join(', '), '1, 2', 'can extract the values from an object');
- equal(_.values({one: 1, two: 2, length: 3}).join(', '), '1, 2, 3', '... even when one of them is "length"');
- });
- `)
- })
-}
-
-// pairs
-func Test_underscore_objects_2(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("pairs", function() {
- deepEqual(_.pairs({one: 1, two: 2}), [['one', 1], ['two', 2]], 'can convert an object into pairs');
- deepEqual(_.pairs({one: 1, two: 2, length: 3}), [['one', 1], ['two', 2], ['length', 3]], '... even when one of them is "length"');
- });
- `)
- })
-}
-
-// invert
-func Test_underscore_objects_3(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("invert", function() {
- var obj = {first: 'Moe', second: 'Larry', third: 'Curly'};
- equal(_.keys(_.invert(obj)).join(' '), 'Moe Larry Curly', 'can invert an object');
- ok(_.isEqual(_.invert(_.invert(obj)), obj), 'two inverts gets you back where you started');
-
- var obj = {length: 3};
- ok(_.invert(obj)['3'] == 'length', 'can invert an object with "length"')
- });
- `)
- })
-}
-
-// functions
-func Test_underscore_objects_4(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("functions", function() {
- var obj = {a : 'dash', b : _.map, c : (/yo/), d : _.reduce};
- ok(_.isEqual(['b', 'd'], _.functions(obj)), 'can grab the function names of any passed-in object');
-
- var Animal = function(){};
- Animal.prototype.run = function(){};
- equal(_.functions(new Animal).join(''), 'run', 'also looks up functions on the prototype');
- });
- `)
- })
-}
-
-// extend
-func Test_underscore_objects_5(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("extend", function() {
- var result;
- equal(_.extend({}, {a:'b'}).a, 'b', 'can extend an object with the attributes of another');
- equal(_.extend({a:'x'}, {a:'b'}).a, 'b', 'properties in source override destination');
- equal(_.extend({x:'x'}, {a:'b'}).x, 'x', 'properties not in source dont get overriden');
- result = _.extend({x:'x'}, {a:'a'}, {b:'b'});
- ok(_.isEqual(result, {x:'x', a:'a', b:'b'}), 'can extend from multiple source objects');
- result = _.extend({x:'x'}, {a:'a', x:2}, {a:'b'});
- ok(_.isEqual(result, {x:2, a:'b'}), 'extending from multiple source objects last property trumps');
- result = _.extend({}, {a: void 0, b: null});
- equal(_.keys(result).join(''), 'ab', 'extend does not copy undefined values');
-
- try {
- result = {};
- _.extend(result, null, undefined, {a:1});
- } catch(ex) {}
-
- equal(result.a, 1, 'should not error on <null> or <undefined> sources');
- });
- `)
- })
-}
-
-// pick
-func Test_underscore_objects_6(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("pick", function() {
- var result;
- result = _.pick({a:1, b:2, c:3}, 'a', 'c');
- ok(_.isEqual(result, {a:1, c:3}), 'can restrict properties to those named');
- result = _.pick({a:1, b:2, c:3}, ['b', 'c']);
- ok(_.isEqual(result, {b:2, c:3}), 'can restrict properties to those named in an array');
- result = _.pick({a:1, b:2, c:3}, ['a'], 'b');
- ok(_.isEqual(result, {a:1, b:2}), 'can restrict properties to those named in mixed args');
-
- var Obj = function(){};
- Obj.prototype = {a: 1, b: 2, c: 3};
- ok(_.isEqual(_.pick(new Obj, 'a', 'c'), {a:1, c: 3}), 'include prototype props');
- });
- `)
- })
-}
-
-// omit
-func Test_underscore_objects_7(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("omit", function() {
- var result;
- result = _.omit({a:1, b:2, c:3}, 'b');
- ok(_.isEqual(result, {a:1, c:3}), 'can omit a single named property');
- result = _.omit({a:1, b:2, c:3}, 'a', 'c');
- ok(_.isEqual(result, {b:2}), 'can omit several named properties');
- result = _.omit({a:1, b:2, c:3}, ['b', 'c']);
- ok(_.isEqual(result, {a:1}), 'can omit properties named in an array');
-
- var Obj = function(){};
- Obj.prototype = {a: 1, b: 2, c: 3};
- ok(_.isEqual(_.omit(new Obj, 'b'), {a:1, c: 3}), 'include prototype props');
- });
- `)
- })
-}
-
-// defaults
-func Test_underscore_objects_8(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("defaults", function() {
- var result;
- var options = {zero: 0, one: 1, empty: "", nan: NaN, string: "string"};
-
- _.defaults(options, {zero: 1, one: 10, twenty: 20});
- equal(options.zero, 0, 'value exists');
- equal(options.one, 1, 'value exists');
- equal(options.twenty, 20, 'default applied');
-
- _.defaults(options, {empty: "full"}, {nan: "nan"}, {word: "word"}, {word: "dog"});
- equal(options.empty, "", 'value exists');
- ok(_.isNaN(options.nan), "NaN isn't overridden");
- equal(options.word, "word", 'new value is added, first one wins');
-
- try {
- options = {};
- _.defaults(options, null, undefined, {a:1});
- } catch(ex) {}
-
- equal(options.a, 1, 'should not error on <null> or <undefined> sources');
- });
- `)
- })
-}
-
-// clone
-func Test_underscore_objects_9(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("clone", function() {
- var moe = {name : 'moe', lucky : [13, 27, 34]};
- var clone = _.clone(moe);
- equal(clone.name, 'moe', 'the clone as the attributes of the original');
-
- clone.name = 'curly';
- ok(clone.name == 'curly' && moe.name == 'moe', 'clones can change shallow attributes without affecting the original');
-
- clone.lucky.push(101);
- equal(_.last(moe.lucky), 101, 'changes to deep attributes are shared with the original');
-
- equal(_.clone(undefined), void 0, 'non objects should not be changed by clone');
- equal(_.clone(1), 1, 'non objects should not be changed by clone');
- equal(_.clone(null), null, 'non objects should not be changed by clone');
- });
- `)
- })
-}
-
-// isEqual
-func Test_underscore_objects_10(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("isEqual", function() {
- function First() {
- this.value = 1;
- }
- First.prototype.value = 1;
- function Second() {
- this.value = 1;
- }
- Second.prototype.value = 2;
-
- // Basic equality and identity comparisons.
- ok(_.isEqual(null, null), "<null> is equal to <null>");
- ok(_.isEqual(), "<undefined> is equal to <undefined>");
-
- ok(!_.isEqual(0, -0), "<0> is not equal to <-0>");
- ok(!_.isEqual(-0, 0), "Commutative equality is implemented for <0> and <-0>");
- ok(!_.isEqual(null, undefined), "<null> is not equal to <undefined>");
- ok(!_.isEqual(undefined, null), "Commutative equality is implemented for <null> and <undefined>");
-
- // String object and primitive comparisons.
- ok(_.isEqual("Curly", "Curly"), "Identical string primitives are equal");
- ok(_.isEqual(new String("Curly"), new String("Curly")), "String objects with identical primitive values are equal");
- ok(_.isEqual(new String("Curly"), "Curly"), "String primitives and their corresponding object wrappers are equal");
- ok(_.isEqual("Curly", new String("Curly")), "Commutative equality is implemented for string objects and primitives");
-
- ok(!_.isEqual("Curly", "Larry"), "String primitives with different values are not equal");
- ok(!_.isEqual(new String("Curly"), new String("Larry")), "String objects with different primitive values are not equal");
- ok(!_.isEqual(new String("Curly"), {toString: function(){ return "Curly"; }}), "String objects and objects with a custom <toString> method are not equal");
-
- // Number object and primitive comparisons.
- ok(_.isEqual(75, 75), "Identical number primitives are equal");
- ok(_.isEqual(new Number(75), new Number(75)), "Number objects with identical primitive values are equal");
- ok(_.isEqual(75, new Number(75)), "Number primitives and their corresponding object wrappers are equal");
- ok(_.isEqual(new Number(75), 75), "Commutative equality is implemented for number objects and primitives");
- ok(!_.isEqual(new Number(0), -0), "<new Number(0)> and <-0> are not equal");
- ok(!_.isEqual(0, new Number(-0)), "Commutative equality is implemented for <new Number(0)> and <-0>");
-
- ok(!_.isEqual(new Number(75), new Number(63)), "Number objects with different primitive values are not equal");
- ok(!_.isEqual(new Number(63), {valueOf: function(){ return 63; }}), "Number objects and objects with a <valueOf> method are not equal");
-
- // Comparisons involving <NaN>.
- ok(_.isEqual(NaN, NaN), "<NaN> is equal to <NaN>");
- ok(!_.isEqual(61, NaN), "A number primitive is not equal to <NaN>");
- ok(!_.isEqual(new Number(79), NaN), "A number object is not equal to <NaN>");
- ok(!_.isEqual(Infinity, NaN), "<Infinity> is not equal to <NaN>");
-
- // Boolean object and primitive comparisons.
- ok(_.isEqual(true, true), "Identical boolean primitives are equal");
- ok(_.isEqual(new Boolean, new Boolean), "Boolean objects with identical primitive values are equal");
- ok(_.isEqual(true, new Boolean(true)), "Boolean primitives and their corresponding object wrappers are equal");
- ok(_.isEqual(new Boolean(true), true), "Commutative equality is implemented for booleans");
- ok(!_.isEqual(new Boolean(true), new Boolean), "Boolean objects with different primitive values are not equal");
-
- // Common type coercions.
- ok(!_.isEqual(true, new Boolean(false)), "Boolean objects are not equal to the boolean primitive <true>");
- ok(!_.isEqual("75", 75), "String and number primitives with like values are not equal");
- ok(!_.isEqual(new Number(63), new String(63)), "String and number objects with like values are not equal");
- ok(!_.isEqual(75, "75"), "Commutative equality is implemented for like string and number values");
- ok(!_.isEqual(0, ""), "Number and string primitives with like values are not equal");
- ok(!_.isEqual(1, true), "Number and boolean primitives with like values are not equal");
- ok(!_.isEqual(new Boolean(false), new Number(0)), "Boolean and number objects with like values are not equal");
- ok(!_.isEqual(false, new String("")), "Boolean primitives and string objects with like values are not equal");
- ok(!_.isEqual(12564504e5, new Date(2009, 9, 25)), "Dates and their corresponding numeric primitive values are not equal");
-
- // Dates.
- ok(_.isEqual(new Date(2009, 9, 25), new Date(2009, 9, 25)), "Date objects referencing identical times are equal");
- ok(!_.isEqual(new Date(2009, 9, 25), new Date(2009, 11, 13)), "Date objects referencing different times are not equal");
- ok(!_.isEqual(new Date(2009, 11, 13), {
- getTime: function(){
- return 12606876e5;
- }
- }), "Date objects and objects with a <getTime> method are not equal");
- ok(!_.isEqual(new Date("Curly"), new Date("Curly")), "Invalid dates are not equal");
-
- // Functions.
- ok(!_.isEqual(First, Second), "Different functions with identical bodies and source code representations are not equal");
-
- // RegExps.
- ok(_.isEqual(/(?:)/gim, /(?:)/gim), "RegExps with equivalent patterns and flags are equal");
- ok(!_.isEqual(/(?:)/g, /(?:)/gi), "RegExps with equivalent patterns and different flags are not equal");
- ok(!_.isEqual(/Moe/gim, /Curly/gim), "RegExps with different patterns and equivalent flags are not equal");
- ok(!_.isEqual(/(?:)/gi, /(?:)/g), "Commutative equality is implemented for RegExps");
- ok(!_.isEqual(/Curly/g, {source: "Larry", global: true, ignoreCase: false, multiline: false}), "RegExps and RegExp-like objects are not equal");
-
- // Empty arrays, array-like objects, and object literals.
- ok(_.isEqual({}, {}), "Empty object literals are equal");
- ok(_.isEqual([], []), "Empty array literals are equal");
- ok(_.isEqual([{}], [{}]), "Empty nested arrays and objects are equal");
- ok(!_.isEqual({length: 0}, []), "Array-like objects and arrays are not equal.");
- ok(!_.isEqual([], {length: 0}), "Commutative equality is implemented for array-like objects");
-
- ok(!_.isEqual({}, []), "Object literals and array literals are not equal");
- ok(!_.isEqual([], {}), "Commutative equality is implemented for objects and arrays");
-
- // Arrays with primitive and object values.
- ok(_.isEqual([1, "Larry", true], [1, "Larry", true]), "Arrays containing identical primitives are equal");
- ok(_.isEqual([(/Moe/g), new Date(2009, 9, 25)], [(/Moe/g), new Date(2009, 9, 25)]), "Arrays containing equivalent elements are equal");
-
- // Multi-dimensional arrays.
- var a = [new Number(47), false, "Larry", /Moe/, new Date(2009, 11, 13), ['running', 'biking', new String('programming')], {a: 47}];
- var b = [new Number(47), false, "Larry", /Moe/, new Date(2009, 11, 13), ['running', 'biking', new String('programming')], {a: 47}];
- ok(_.isEqual(a, b), "Arrays containing nested arrays and objects are recursively compared");
-
- // Overwrite the methods defined in ES 5.1 section 15.4.4.
- a.forEach = a.map = a.filter = a.every = a.indexOf = a.lastIndexOf = a.some = a.reduce = a.reduceRight = null;
- b.join = b.pop = b.reverse = b.shift = b.slice = b.splice = b.concat = b.sort = b.unshift = null;
-
- // Array elements and properties.
- ok(_.isEqual(a, b), "Arrays containing equivalent elements and different non-numeric properties are equal");
- a.push("White Rocks");
- ok(!_.isEqual(a, b), "Arrays of different lengths are not equal");
- a.push("East Boulder");
- b.push("Gunbarrel Ranch", "Teller Farm");
- ok(!_.isEqual(a, b), "Arrays of identical lengths containing different elements are not equal");
-
- // Sparse arrays.
- ok(_.isEqual(Array(3), Array(3)), "Sparse arrays of identical lengths are equal");
- ok(!_.isEqual(Array(3), Array(6)), "Sparse arrays of different lengths are not equal when both are empty");
-
- // Simple objects.
- ok(_.isEqual({a: "Curly", b: 1, c: true}, {a: "Curly", b: 1, c: true}), "Objects containing identical primitives are equal");
- ok(_.isEqual({a: /Curly/g, b: new Date(2009, 11, 13)}, {a: /Curly/g, b: new Date(2009, 11, 13)}), "Objects containing equivalent members are equal");
- ok(!_.isEqual({a: 63, b: 75}, {a: 61, b: 55}), "Objects of identical sizes with different values are not equal");
- ok(!_.isEqual({a: 63, b: 75}, {a: 61, c: 55}), "Objects of identical sizes with different property names are not equal");
- ok(!_.isEqual({a: 1, b: 2}, {a: 1}), "Objects of different sizes are not equal");
- ok(!_.isEqual({a: 1}, {a: 1, b: 2}), "Commutative equality is implemented for objects");
- ok(!_.isEqual({x: 1, y: undefined}, {x: 1, z: 2}), "Objects with identical keys and different values are not equivalent");
-
- // <A> contains nested objects and arrays.
- a = {
- name: new String("Moe Howard"),
- age: new Number(77),
- stooge: true,
- hobbies: ["acting"],
- film: {
- name: "Sing a Song of Six Pants",
- release: new Date(1947, 9, 30),
- stars: [new String("Larry Fine"), "Shemp Howard"],
- minutes: new Number(16),
- seconds: 54
- }
- };
-
- // <B> contains equivalent nested objects and arrays.
- b = {
- name: new String("Moe Howard"),
- age: new Number(77),
- stooge: true,
- hobbies: ["acting"],
- film: {
- name: "Sing a Song of Six Pants",
- release: new Date(1947, 9, 30),
- stars: [new String("Larry Fine"), "Shemp Howard"],
- minutes: new Number(16),
- seconds: 54
- }
- };
- ok(_.isEqual(a, b), "Objects with nested equivalent members are recursively compared");
-
- // Instances.
- ok(_.isEqual(new First, new First), "Object instances are equal");
- ok(!_.isEqual(new First, new Second), "Objects with different constructors and identical own properties are not equal");
- ok(!_.isEqual({value: 1}, new First), "Object instances and objects sharing equivalent properties are not equal");
- ok(!_.isEqual({value: 2}, new Second), "The prototype chain of objects should not be examined");
-
- // Circular Arrays.
- (a = []).push(a);
- (b = []).push(b);
- ok(_.isEqual(a, b), "Arrays containing circular references are equal");
- a.push(new String("Larry"));
- b.push(new String("Larry"));
- ok(_.isEqual(a, b), "Arrays containing circular references and equivalent properties are equal");
- a.push("Shemp");
- b.push("Curly");
- ok(!_.isEqual(a, b), "Arrays containing circular references and different properties are not equal");
-
- // More circular arrays #767.
- a = ["everything is checked but", "this", "is not"];
- a[1] = a;
- b = ["everything is checked but", ["this", "array"], "is not"];
- ok(!_.isEqual(a, b), "Comparison of circular references with non-circular references are not equal");
-
- // Circular Objects.
- a = {abc: null};
- b = {abc: null};
- a.abc = a;
- b.abc = b;
- ok(_.isEqual(a, b), "Objects containing circular references are equal");
- a.def = 75;
- b.def = 75;
- ok(_.isEqual(a, b), "Objects containing circular references and equivalent properties are equal");
- a.def = new Number(75);
- b.def = new Number(63);
- ok(!_.isEqual(a, b), "Objects containing circular references and different properties are not equal");
-
- // More circular objects #767.
- a = {everything: "is checked", but: "this", is: "not"};
- a.but = a;
- b = {everything: "is checked", but: {that:"object"}, is: "not"};
- ok(!_.isEqual(a, b), "Comparison of circular references with non-circular object references are not equal");
-
- // Cyclic Structures.
- a = [{abc: null}];
- b = [{abc: null}];
- (a[0].abc = a).push(a);
- (b[0].abc = b).push(b);
- ok(_.isEqual(a, b), "Cyclic structures are equal");
- a[0].def = "Larry";
- b[0].def = "Larry";
- ok(_.isEqual(a, b), "Cyclic structures containing equivalent properties are equal");
- a[0].def = new String("Larry");
- b[0].def = new String("Curly");
- ok(!_.isEqual(a, b), "Cyclic structures containing different properties are not equal");
-
- // Complex Circular References.
- a = {foo: {b: {foo: {c: {foo: null}}}}};
- b = {foo: {b: {foo: {c: {foo: null}}}}};
- a.foo.b.foo.c.foo = a;
- b.foo.b.foo.c.foo = b;
- ok(_.isEqual(a, b), "Cyclic structures with nested and identically-named properties are equal");
-
- // Chaining.
- ok(!_.isEqual(_({x: 1, y: undefined}).chain(), _({x: 1, z: 2}).chain()), 'Chained objects containing different values are not equal');
-
- a = _({x: 1, y: 2}).chain();
- b = _({x: 1, y: 2}).chain();
- equal(_.isEqual(a.isEqual(b), _(true)), true, '<isEqual> can be chained');
-
- // TEST: ???
- return;
-
- // Objects from another frame.
- ok(_.isEqual({}, iObject));
- });
- `)
- })
-}
-
-// isEmpty
-func Test_underscore_objects_11(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("isEmpty", function() {
- ok(!_([1]).isEmpty(), '[1] is not empty');
- ok(_.isEmpty([]), '[] is empty');
- ok(!_.isEmpty({one : 1}), '{one : 1} is not empty');
- ok(_.isEmpty({}), '{} is empty');
- ok(_.isEmpty(new RegExp('')), 'objects with prototype properties are empty');
- ok(_.isEmpty(null), 'null is empty');
- ok(_.isEmpty(), 'undefined is empty');
- ok(_.isEmpty(''), 'the empty string is empty');
- ok(!_.isEmpty('moe'), 'but other strings are not');
-
- var obj = {one : 1};
- delete obj.one;
- ok(_.isEmpty(obj), 'deleting all the keys from an object empties it');
- });
- `)
- })
-}
-
-// isElement
-func Test_underscore_objects_12(t *testing.T) {
- // TEST: ReferenceError: $ is not defined
- if true {
- return
- }
-
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("isElement", function() {
- ok(!_.isElement('div'), 'strings are not dom elements');
- ok(_.isElement($('html')[0]), 'the html tag is a DOM element');
- ok(_.isElement(iElement), 'even from another frame');
- });
- `)
- })
-}
-
-// isArguments
-func Test_underscore_objects_13(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("isArguments", function() {
- var args = (function(){ return arguments; })(1, 2, 3);
- ok(!_.isArguments('string'), 'a string is not an arguments object');
- ok(!_.isArguments(_.isArguments), 'a function is not an arguments object');
- ok(_.isArguments(args), 'but the arguments object is an arguments object');
- ok(!_.isArguments(_.toArray(args)), 'but not when it\'s converted into an array');
- ok(!_.isArguments([1,2,3]), 'and not vanilla arrays.');
-
- // TEST: ReferenceError: iArguments is not defined
- return;
- ok(_.isArguments(iArguments), 'even from another frame');
- });
- `)
- })
-}
-
-// isObject
-func Test_underscore_objects_14(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("isObject", function() {
- ok(_.isObject(arguments), 'the arguments object is object');
- ok(_.isObject([1, 2, 3]), 'and arrays');
- // TEST: ReferenceError: $ is not defined
- return;
- ok(_.isObject($('html')[0]), 'and DOM element');
- ok(_.isObject(iElement), 'even from another frame');
- ok(_.isObject(function () {}), 'and functions');
- ok(_.isObject(iFunction), 'even from another frame');
- ok(!_.isObject(null), 'but not null');
- ok(!_.isObject(undefined), 'and not undefined');
- ok(!_.isObject('string'), 'and not string');
- ok(!_.isObject(12), 'and not number');
- ok(!_.isObject(true), 'and not boolean');
- ok(_.isObject(new String('string')), 'but new String()');
- });
- `)
- })
-}
-
-// isArray
-func Test_underscore_objects_15(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("isArray", function() {
- ok(!_.isArray(arguments), 'the arguments object is not an array');
- ok(_.isArray([1, 2, 3]), 'but arrays are');
- // TEST: ???
- return;
- ok(_.isArray(iArray), 'even from another frame');
- });
- `)
- })
-}
-
-// isString
-func Test_underscore_objects_16(t *testing.T) {
- // TEST: ReferenceError: document is not defined
- if true {
- return
- }
-
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("isString", function() {
- ok(!_.isString(document.body), 'the document body is not a string');
- ok(_.isString([1, 2, 3].join(', ')), 'but strings are');
- // TEST: ???
- return;
- ok(_.isString(iString), 'even from another frame');
- });
- `)
- })
-}
-
-// isNumber
-func Test_underscore_objects_17(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("isNumber", function() {
- ok(!_.isNumber('string'), 'a string is not a number');
- ok(!_.isNumber(arguments), 'the arguments object is not a number');
- ok(!_.isNumber(undefined), 'undefined is not a number');
- ok(_.isNumber(3 * 4 - 7 / 10), 'but numbers are');
- ok(_.isNumber(NaN), 'NaN *is* a number');
- ok(_.isNumber(Infinity), 'Infinity is a number');
- // TEST: ???
- return;
- ok(_.isNumber(iNumber), 'even from another frame');
- ok(!_.isNumber('1'), 'numeric strings are not numbers');
- });
- `)
- })
-}
-
-// isBoolean
-func Test_underscore_objects_18(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("isBoolean", function() {
- ok(!_.isBoolean(2), 'a number is not a boolean');
- ok(!_.isBoolean("string"), 'a string is not a boolean');
- ok(!_.isBoolean("false"), 'the string "false" is not a boolean');
- ok(!_.isBoolean("true"), 'the string "true" is not a boolean');
- ok(!_.isBoolean(arguments), 'the arguments object is not a boolean');
- ok(!_.isBoolean(undefined), 'undefined is not a boolean');
- ok(!_.isBoolean(NaN), 'NaN is not a boolean');
- ok(!_.isBoolean(null), 'null is not a boolean');
- ok(_.isBoolean(true), 'but true is');
- ok(_.isBoolean(false), 'and so is false');
- // TEST: ???
- return;
- ok(_.isBoolean(iBoolean), 'even from another frame');
- });
- `)
- })
-}
-
-// isFunction
-func Test_underscore_objects_19(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("isFunction", function() {
- ok(!_.isFunction([1, 2, 3]), 'arrays are not functions');
- ok(!_.isFunction('moe'), 'strings are not functions');
- ok(_.isFunction(_.isFunction), 'but functions are');
- // TEST: ???
- return;
- ok(_.isFunction(iFunction), 'even from another frame');
- });
- `)
- })
-}
-
-// isDate
-func Test_underscore_objects_20(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("isDate", function() {
- ok(!_.isDate(100), 'numbers are not dates');
- ok(!_.isDate({}), 'objects are not dates');
- ok(_.isDate(new Date()), 'but dates are');
- // TEST: ???
- return;
- ok(_.isDate(iDate), 'even from another frame');
- });
- `)
- })
-}
-
-// isRegExp
-func Test_underscore_objects_21(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("isRegExp", function() {
- ok(!_.isRegExp(_.identity), 'functions are not RegExps');
- ok(_.isRegExp(/identity/), 'but RegExps are');
- // TEST: ???
- return;
- ok(_.isRegExp(iRegExp), 'even from another frame');
- });
- `)
- })
-}
-
-// isFinite
-func Test_underscore_objects_22(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("isFinite", function() {
- ok(!_.isFinite(undefined), 'undefined is not Finite');
- ok(!_.isFinite(null), 'null is not Finite');
- ok(!_.isFinite(NaN), 'NaN is not Finite');
- ok(!_.isFinite(Infinity), 'Infinity is not Finite');
- ok(!_.isFinite(-Infinity), '-Infinity is not Finite');
- ok(_.isFinite('12'), 'Numeric strings are numbers');
- ok(!_.isFinite('1a'), 'Non numeric strings are not numbers');
- ok(!_.isFinite(''), 'Empty strings are not numbers');
- var obj = new Number(5);
- ok(_.isFinite(obj), 'Number instances can be finite');
- ok(_.isFinite(0), '0 is Finite');
- ok(_.isFinite(123), 'Ints are Finite');
- ok(_.isFinite(-12.44), 'Floats are Finite');
- });
- `)
- })
-}
-
-// isNaN
-func Test_underscore_objects_23(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("isNaN", function() {
- ok(!_.isNaN(undefined), 'undefined is not NaN');
- ok(!_.isNaN(null), 'null is not NaN');
- ok(!_.isNaN(0), '0 is not NaN');
- ok(_.isNaN(NaN), 'but NaN is');
- // TEST: ???
- return;
- ok(_.isNaN(iNaN), 'even from another frame');
- ok(_.isNaN(new Number(NaN)), 'wrapped NaN is still NaN');
- });
- `)
- })
-}
-
-// isNull
-func Test_underscore_objects_24(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("isNull", function() {
- ok(!_.isNull(undefined), 'undefined is not null');
- ok(!_.isNull(NaN), 'NaN is not null');
- ok(_.isNull(null), 'but null is');
- // TEST: ???
- return;
- ok(_.isNull(iNull), 'even from another frame');
- });
- `)
- })
-}
-
-// isUndefined
-func Test_underscore_objects_25(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("isUndefined", function() {
- ok(!_.isUndefined(1), 'numbers are defined');
- ok(!_.isUndefined(null), 'null is defined');
- ok(!_.isUndefined(false), 'false is defined');
- ok(!_.isUndefined(NaN), 'NaN is defined');
- ok(_.isUndefined(), 'nothing is undefined');
- ok(_.isUndefined(undefined), 'undefined is undefined');
- // TEST: ???
- return;
- ok(_.isUndefined(iUndefined), 'even from another frame');
- });
- `)
- })
-}
-
-// tap
-func Test_underscore_objects_26(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("tap", function() {
- var intercepted = null;
- var interceptor = function(obj) { intercepted = obj; };
- var returned = _.tap(1, interceptor);
- equal(intercepted, 1, "passes tapped object to interceptor");
- equal(returned, 1, "returns tapped object");
-
- returned = _([1,2,3]).chain().
- map(function(n){ return n * 2; }).
- max().
- tap(interceptor).
- value();
- ok(returned == 6 && intercepted == 6, 'can use tapped objects in a chain');
- });
- `)
- })
-}
-
-// has
-func Test_underscore_objects_27(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("has", function () {
- var obj = {foo: "bar", func: function () {} };
- ok (_.has(obj, "foo"), "has() checks that the object has a property.");
- ok (_.has(obj, "baz") == false, "has() returns false if the object doesn't have the property.");
- ok (_.has(obj, "func"), "has() works for functions too.");
- obj.hasOwnProperty = null;
- ok (_.has(obj, "foo"), "has() works even when the hasOwnProperty method is deleted.");
- var child = {};
- child.prototype = obj;
- ok (_.has(child, "foo") == false, "has() does not check the prototype chain for a property.")
- });
- `)
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_test.go
deleted file mode 100644
index d8bf2da18..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_test.go
+++ /dev/null
@@ -1,165 +0,0 @@
-package otto
-
-import (
- "./terst"
- "testing"
-
- "github.com/robertkrimen/otto/underscore"
-)
-
-func init() {
- underscore.Disable()
-}
-
-// A persistent handle for the underscore tester
-// We do not run underscore tests in parallel, so it is okay to stash globally
-// (Maybe use sync.Pool in the future...)
-var tester_ *_tester
-
-// A tester for underscore: test_ => test(underscore) :)
-func test_(arguments ...interface{}) (func(string, ...interface{}) Value, *_tester) {
- tester := tester_
- if tester == nil {
- tester = newTester()
- tester.underscore() // Load underscore and testing shim, etc.
- tester_ = tester
- }
-
- return tester.test, tester
-}
-
-func (self *_tester) underscore() {
- vm := self.vm
- _, err := vm.Run(underscore.Source())
- if err != nil {
- panic(err)
- }
-
- vm.Set("assert", func(call FunctionCall) Value {
- if !call.Argument(0).bool() {
- message := "Assertion failed"
- if len(call.ArgumentList) > 1 {
- message = call.ArgumentList[1].string()
- }
- t := terst.Caller().T()
- is(message, nil)
- t.Fail()
- return falseValue
- }
- return trueValue
- })
-
- vm.Run(`
- var templateSettings;
-
- function _setup() {
- templateSettings = _.clone(_.templateSettings);
- }
-
- function _teardown() {
- _.templateSettings = templateSettings;
- }
-
- function module() {
- /* Nothing happens. */
- }
-
- function equals(a, b, emit) {
- assert(a == b, emit + ", <" + a + "> != <" + b + ">");
- }
- var equal = equals;
-
- function notStrictEqual(a, b, emit) {
- assert(a !== b, emit);
- }
-
- function strictEqual(a, b, emit) {
- assert(a === b, emit);
- }
-
- function ok(a, emit) {
- assert(a, emit);
- }
-
- function raises(fn, want, emit) {
- var have, _ok = false;
- if (typeof want === "string") {
- emit = want;
- want = null;
- }
-
- try {
- fn();
- } catch(tmp) {
- have = tmp;
- }
-
- if (have) {
- if (!want) {
- _ok = true;
- }
- else if (want instanceof RegExp) {
- _ok = want.test(have);
- }
- else if (have instanceof want) {
- _ok = true
- }
- else if (want.call({}, have) === true) {
- _ok = true;
- }
- }
-
- ok(_ok, emit);
- }
-
- function test(name){
- _setup()
- try {
- templateSettings = _.clone(_.templateSettings);
- if (arguments.length == 3) {
- count = 0
- for (count = 0; count < arguments[1]; count++) {
- arguments[2]()
- }
- } else {
- // For now.
- arguments[1]()
- }
- }
- finally {
- _teardown()
- }
- }
-
- function deepEqual(a, b, emit) {
- // Also, for now.
- assert(_.isEqual(a, b), emit)
- }
- `)
-}
-
-func Test_underscore(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- _.map([1, 2, 3], function(value){
- return value + 1
- })
- `, "2,3,4")
-
- test(`
- abc = _.find([1, 2, 3, -1], function(value) { return value == -1 })
- `, -1)
-
- test(`_.isEqual(1, 1)`, true)
- test(`_.isEqual([], [])`, true)
- test(`_.isEqual(['b', 'd'], ['b', 'd'])`, true)
- test(`_.isEqual(['b', 'd', 'c'], ['b', 'd', 'e'])`, false)
- test(`_.isFunction(function(){})`, true)
- test(`_.template('<p>\u2028<%= "\\u2028\\u2029" %>\u2029</p>')()`, "<p>\u2028\u2028\u2029\u2029</p>")
- })
-}
-
-// TODO Test: typeof An argument reference
-// TODO Test: abc = {}; abc == Object(abc)
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_utility_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_utility_test.go
deleted file mode 100644
index ebabb083b..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/underscore_utility_test.go
+++ /dev/null
@@ -1,419 +0,0 @@
-package otto
-
-import (
- "testing"
-)
-
-// #750 - Return _ instance.
-func Test_underscore_utility_0(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("#750 - Return _ instance.", 2, function() {
- var instance = _([]);
- ok(_(instance) === instance);
- ok(new _(instance) === instance);
- });
- `)
- })
-}
-
-// identity
-func Test_underscore_utility_1(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("identity", function() {
- var moe = {name : 'moe'};
- equal(_.identity(moe), moe, 'moe is the same as his identity');
- });
- `)
- })
-}
-
-// random
-func Test_underscore_utility_2(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("random", function() {
- var array = _.range(1000);
- var min = Math.pow(2, 31);
- var max = Math.pow(2, 62);
-
- ok(_.every(array, function() {
- return _.random(min, max) >= min;
- }), "should produce a random number greater than or equal to the minimum number");
-
- ok(_.some(array, function() {
- return _.random(Number.MAX_VALUE) > 0;
- }), "should produce a random number when passed <Number.MAX_VALUE>");
- });
- `)
- })
-}
-
-// uniqueId
-func Test_underscore_utility_3(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("uniqueId", function() {
- var ids = [], i = 0;
- while(i++ < 100) ids.push(_.uniqueId());
- equal(_.uniq(ids).length, ids.length, 'can generate a globally-unique stream of ids');
- });
- `)
- })
-}
-
-// times
-func Test_underscore_utility_4(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("times", function() {
- var vals = [];
- _.times(3, function (i) { vals.push(i); });
- ok(_.isEqual(vals, [0,1,2]), "is 0 indexed");
- //
- vals = [];
- _(3).times(function(i) { vals.push(i); });
- ok(_.isEqual(vals, [0,1,2]), "works as a wrapper");
- // collects return values
- ok(_.isEqual([0, 1, 2], _.times(3, function(i) { return i; })), "collects return values");
- });
- `)
- })
-}
-
-// mixin
-func Test_underscore_utility_5(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("mixin", function() {
- _.mixin({
- myReverse: function(string) {
- return string.split('').reverse().join('');
- }
- });
- equal(_.myReverse('panacea'), 'aecanap', 'mixed in a function to _');
- equal(_('champ').myReverse(), 'pmahc', 'mixed in a function to the OOP wrapper');
- });
- `)
- })
-}
-
-// _.escape
-func Test_underscore_utility_6(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("_.escape", function() {
- equal(_.escape("Curly & Moe"), "Curly &amp; Moe");
- equal(_.escape("Curly &amp; Moe"), "Curly &amp;amp; Moe");
- equal(_.escape(null), '');
- });
- `)
- })
-}
-
-// _.unescape
-func Test_underscore_utility_7(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("_.unescape", function() {
- var string = "Curly & Moe";
- equal(_.unescape("Curly &amp; Moe"), string);
- equal(_.unescape("Curly &amp;amp; Moe"), "Curly &amp; Moe");
- equal(_.unescape(null), '');
- equal(_.unescape(_.escape(string)), string);
- });
- `)
- })
-}
-
-// template
-func Test_underscore_utility_8(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test("template", function() {
- var basicTemplate = _.template("<%= thing %> is gettin' on my noives!");
- var result = basicTemplate({thing : 'This'});
- equal(result, "This is gettin' on my noives!", 'can do basic attribute interpolation');
-
- var sansSemicolonTemplate = _.template("A <% this %> B");
- equal(sansSemicolonTemplate(), "A B");
-
- var backslashTemplate = _.template("<%= thing %> is \\ridanculous");
- equal(backslashTemplate({thing: 'This'}), "This is \\ridanculous");
-
- var escapeTemplate = _.template('<%= a ? "checked=\\"checked\\"" : "" %>');
- equal(escapeTemplate({a: true}), 'checked="checked"', 'can handle slash escapes in interpolations.');
-
- var fancyTemplate = _.template("<ul><% \
- for (var key in people) { \
- %><li><%= people[key] %></li><% } %></ul>");
- result = fancyTemplate({people : {moe : "Moe", larry : "Larry", curly : "Curly"}});
- equal(result, "<ul><li>Moe</li><li>Larry</li><li>Curly</li></ul>", 'can run arbitrary javascript in templates');
-
- var escapedCharsInJavascriptTemplate = _.template("<ul><% _.each(numbers.split('\\n'), function(item) { %><li><%= item %></li><% }) %></ul>");
- result = escapedCharsInJavascriptTemplate({numbers: "one\ntwo\nthree\nfour"});
- equal(result, "<ul><li>one</li><li>two</li><li>three</li><li>four</li></ul>", 'Can use escaped characters (e.g. \\n) in Javascript');
-
- var namespaceCollisionTemplate = _.template("<%= pageCount %> <%= thumbnails[pageCount] %> <% _.each(thumbnails, function(p) { %><div class=\"thumbnail\" rel=\"<%= p %>\"></div><% }); %>");
- result = namespaceCollisionTemplate({
- pageCount: 3,
- thumbnails: {
- 1: "p1-thumbnail.gif",
- 2: "p2-thumbnail.gif",
- 3: "p3-thumbnail.gif"
- }
- });
- equal(result, "3 p3-thumbnail.gif <div class=\"thumbnail\" rel=\"p1-thumbnail.gif\"></div><div class=\"thumbnail\" rel=\"p2-thumbnail.gif\"></div><div class=\"thumbnail\" rel=\"p3-thumbnail.gif\"></div>");
-
- var noInterpolateTemplate = _.template("<div><p>Just some text. Hey, I know this is silly but it aids consistency.</p></div>");
- result = noInterpolateTemplate();
- equal(result, "<div><p>Just some text. Hey, I know this is silly but it aids consistency.</p></div>");
-
- var quoteTemplate = _.template("It's its, not it's");
- equal(quoteTemplate({}), "It's its, not it's");
-
- var quoteInStatementAndBody = _.template("<%\
- if(foo == 'bar'){ \
- %>Statement quotes and 'quotes'.<% } %>");
- equal(quoteInStatementAndBody({foo: "bar"}), "Statement quotes and 'quotes'.");
-
- var withNewlinesAndTabs = _.template('This\n\t\tis: <%= x %>.\n\tok.\nend.');
- equal(withNewlinesAndTabs({x: 'that'}), 'This\n\t\tis: that.\n\tok.\nend.');
-
- var template = _.template("<i><%- value %></i>");
- var result = template({value: "<script>"});
- equal(result, '<i>&lt;script&gt;</i>');
-
- var stooge = {
- name: "Moe",
- template: _.template("I'm <%= this.name %>")
- };
- equal(stooge.template(), "I'm Moe");
-
- // TEST: ReferenceError: $ is not defined
- if (false) {
- if (!$.browser.msie) {
- var fromHTML = _.template($('#template').html());
- equal(fromHTML({data : 12345}).replace(/\s/g, ''), '<li>24690</li>');
- }
- }
-
- _.templateSettings = {
- evaluate : /\{\{([\s\S]+?)\}\}/g,
- interpolate : /\{\{=([\s\S]+?)\}\}/g
- };
-
- var custom = _.template("<ul>{{ for (var key in people) { }}<li>{{= people[key] }}</li>{{ } }}</ul>");
- result = custom({people : {moe : "Moe", larry : "Larry", curly : "Curly"}});
- equal(result, "<ul><li>Moe</li><li>Larry</li><li>Curly</li></ul>", 'can run arbitrary javascript in templates');
-
- var customQuote = _.template("It's its, not it's");
- equal(customQuote({}), "It's its, not it's");
-
- var quoteInStatementAndBody = _.template("{{ if(foo == 'bar'){ }}Statement quotes and 'quotes'.{{ } }}");
- equal(quoteInStatementAndBody({foo: "bar"}), "Statement quotes and 'quotes'.");
-
- _.templateSettings = {
- evaluate : /<\?([\s\S]+?)\?>/g,
- interpolate : /<\?=([\s\S]+?)\?>/g
- };
-
- var customWithSpecialChars = _.template("<ul><? for (var key in people) { ?><li><?= people[key] ?></li><? } ?></ul>");
- result = customWithSpecialChars({people : {moe : "Moe", larry : "Larry", curly : "Curly"}});
- equal(result, "<ul><li>Moe</li><li>Larry</li><li>Curly</li></ul>", 'can run arbitrary javascript in templates');
-
- var customWithSpecialCharsQuote = _.template("It's its, not it's");
- equal(customWithSpecialCharsQuote({}), "It's its, not it's");
-
- var quoteInStatementAndBody = _.template("<? if(foo == 'bar'){ ?>Statement quotes and 'quotes'.<? } ?>");
- equal(quoteInStatementAndBody({foo: "bar"}), "Statement quotes and 'quotes'.");
-
- _.templateSettings = {
- interpolate : /\{\{(.+?)\}\}/g
- };
-
- var mustache = _.template("Hello {{planet}}!");
- equal(mustache({planet : "World"}), "Hello World!", "can mimic mustache.js");
-
- var templateWithNull = _.template("a null undefined {{planet}}");
- equal(templateWithNull({planet : "world"}), "a null undefined world", "can handle missing escape and evaluate settings");
- });
- `)
- })
-}
-
-// _.template provides the generated function source, when a SyntaxError occurs
-func Test_underscore_utility_9(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('_.template provides the generated function source, when a SyntaxError occurs', function() {
- try {
- _.template('<b><%= if x %></b>');
- } catch (ex) {
- var source = ex.source;
- }
- ok(/__p/.test(source));
- });
- `)
- })
-}
-
-// _.template handles \\u2028 & \\u2029
-func Test_underscore_utility_10(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('_.template handles \\u2028 & \\u2029', function() {
- var tmpl = _.template('<p>\u2028<%= "\\u2028\\u2029" %>\u2029</p>');
- strictEqual(tmpl(), '<p>\u2028\u2028\u2029\u2029</p>');
- });
- `)
- })
-}
-
-// result calls functions and returns primitives
-func Test_underscore_utility_11(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('result calls functions and returns primitives', function() {
- var obj = {w: '', x: 'x', y: function(){ return this.x; }};
- strictEqual(_.result(obj, 'w'), '');
- strictEqual(_.result(obj, 'x'), 'x');
- strictEqual(_.result(obj, 'y'), 'x');
- strictEqual(_.result(obj, 'z'), undefined);
- strictEqual(_.result(null, 'x'), null);
- });
- `)
- })
-}
-
-// _.templateSettings.variable
-func Test_underscore_utility_12(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('_.templateSettings.variable', function() {
- var s = '<%=data.x%>';
- var data = {x: 'x'};
- strictEqual(_.template(s, data, {variable: 'data'}), 'x');
- _.templateSettings.variable = 'data';
- strictEqual(_.template(s)(data), 'x');
- });
- `)
- })
-}
-
-// #547 - _.templateSettings is unchanged by custom settings.
-func Test_underscore_utility_13(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('#547 - _.templateSettings is unchanged by custom settings.', function() {
- ok(!_.templateSettings.variable);
- _.template('', {}, {variable: 'x'});
- ok(!_.templateSettings.variable);
- });
- `)
- })
-}
-
-// #556 - undefined template variables.
-func Test_underscore_utility_14(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('#556 - undefined template variables.', function() {
- var template = _.template('<%=x%>');
- strictEqual(template({x: null}), '');
- strictEqual(template({x: undefined}), '');
-
- var templateEscaped = _.template('<%-x%>');
- strictEqual(templateEscaped({x: null}), '');
- strictEqual(templateEscaped({x: undefined}), '');
-
- var templateWithProperty = _.template('<%=x.foo%>');
- strictEqual(templateWithProperty({x: {} }), '');
- strictEqual(templateWithProperty({x: {} }), '');
-
- var templateWithPropertyEscaped = _.template('<%-x.foo%>');
- strictEqual(templateWithPropertyEscaped({x: {} }), '');
- strictEqual(templateWithPropertyEscaped({x: {} }), '');
- });
- `)
- })
-}
-
-// interpolate evaluates code only once.
-func Test_underscore_utility_15(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('interpolate evaluates code only once.', 2, function() {
- var count = 0;
- var template = _.template('<%= f() %>');
- template({f: function(){ ok(!(count++)); }});
-
- var countEscaped = 0;
- var templateEscaped = _.template('<%- f() %>');
- templateEscaped({f: function(){ ok(!(countEscaped++)); }});
- });
- `)
- })
-}
-
-// #746 - _.template settings are not modified.
-func Test_underscore_utility_16(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('#746 - _.template settings are not modified.', 1, function() {
- var settings = {};
- _.template('', null, settings);
- deepEqual(settings, {});
- });
- `)
- })
-}
-
-// #779 - delimeters are applied to unescaped text.
-func Test_underscore_utility_17(t *testing.T) {
- tt(t, func() {
- test, _ := test_()
-
- test(`
- test('#779 - delimeters are applied to unescaped text.', 1, function() {
- var template = _.template('<<\nx\n>>', null, {evaluate: /<<(.*?)>>/g});
- strictEqual(template(), '<<\nx\n>>');
- });
- `)
- })
-}
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/value.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/value.go
index 05d61dd62..a1c341f4d 100644
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/value.go
+++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/value.go
@@ -680,15 +680,36 @@ func (self Value) export() interface{} {
result := make([]interface{}, 0)
lengthValue := object.get("length")
length := lengthValue.value.(uint32)
+ kind := reflect.Invalid
+ state := 0
+ var t reflect.Type
for index := uint32(0); index < length; index += 1 {
name := strconv.FormatInt(int64(index), 10)
if !object.hasProperty(name) {
continue
}
- value := object.get(name)
- result = append(result, value.export())
+ value := object.get(name).export()
+ t = reflect.TypeOf(value)
+ if state == 0 {
+ kind = t.Kind()
+ state = 1
+ } else if state == 1 && kind != t.Kind() {
+ state = 2
+ }
+ result = append(result, value)
}
- return result
+
+ if state != 1 || kind == reflect.Interface {
+ // No common type
+ return result
+ }
+
+ // Convert to the common type
+ val := reflect.MakeSlice(reflect.SliceOf(t), len(result), len(result))
+ for i, v := range result {
+ val.Index(i).Set(reflect.ValueOf(v))
+ }
+ return val.Interface()
} else {
result := make(map[string]interface{})
// TODO Should we export everything? Or just what is enumerable?
@@ -770,6 +791,21 @@ func (self Value) exportNative() interface{} {
// Make a best effort to return a reflect.Value corresponding to reflect.Kind, but
// fallback to just returning the Go value we have handy.
func (value Value) toReflectValue(kind reflect.Kind) (reflect.Value, error) {
+ if kind != reflect.Float32 && kind != reflect.Float64 && kind != reflect.Interface {
+ switch value := value.value.(type) {
+ case float32:
+ _, frac := math.Modf(float64(value))
+ if frac > 0 {
+ return reflect.Value{}, fmt.Errorf("RangeError: %v to reflect.Kind: %v", value, kind)
+ }
+ case float64:
+ _, frac := math.Modf(value)
+ if frac > 0 {
+ return reflect.Value{}, fmt.Errorf("RangeError: %v to reflect.Kind: %v", value, kind)
+ }
+ }
+ }
+
switch kind {
case reflect.Bool: // Bool
return reflect.ValueOf(value.bool()), nil
@@ -857,7 +893,7 @@ func (value Value) toReflectValue(kind reflect.Kind) (reflect.Value, error) {
if 0 > tmp1 {
tmp1 = -tmp1
}
- if tmp1 < math.SmallestNonzeroFloat32 || tmp1 > math.MaxFloat32 {
+ if tmp1 > 0 && (tmp1 < math.SmallestNonzeroFloat32 || tmp1 > math.MaxFloat32) {
return reflect.Value{}, fmt.Errorf("RangeError: %f (%v) to float32", tmp, value)
} else {
return reflect.ValueOf(float32(tmp)), nil
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/value_test.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/value_test.go
deleted file mode 100644
index 4a9bd546f..000000000
--- a/Godeps/_workspace/src/github.com/robertkrimen/otto/value_test.go
+++ /dev/null
@@ -1,281 +0,0 @@
-package otto
-
-import (
- "encoding/json"
- "math"
- "testing"
-)
-
-func TestValue(t *testing.T) {
- tt(t, func() {
- value := UndefinedValue()
- is(value.IsUndefined(), true)
- is(value, UndefinedValue())
- is(value, "undefined")
-
- is(toValue(false), false)
- is(toValue(1), 1)
- is(toValue(1).float64(), float64(1))
- })
-}
-
-func TestObject(t *testing.T) {
- tt(t, func() {
- is(emptyValue.isEmpty(), true)
- //is(newObject().Value(), "[object]")
- //is(newBooleanObject(false).Value(), "false")
- //is(newFunctionObject(nil).Value(), "[function]")
- //is(newNumberObject(1).Value(), "1")
- //is(newStringObject("Hello, World.").Value(), "Hello, World.")
- })
-}
-
-type intAlias int
-
-func TestToValue(t *testing.T) {
- tt(t, func() {
- _, tester := test()
- vm := tester.vm
-
- value, _ := vm.ToValue(nil)
- is(value, "undefined")
-
- value, _ = vm.ToValue((*byte)(nil))
- is(value, "undefined")
-
- value, _ = vm.ToValue(intAlias(5))
- is(value, 5)
-
- {
- tmp := new(int)
-
- value, _ = vm.ToValue(&tmp)
- is(value, 0)
-
- *tmp = 1
-
- value, _ = vm.ToValue(&tmp)
- is(value, 1)
-
- tmp = nil
-
- value, _ = vm.ToValue(&tmp)
- is(value, "undefined")
- }
-
- {
- tmp0 := new(int)
- tmp1 := &tmp0
- tmp2 := &tmp1
-
- value, _ = vm.ToValue(&tmp2)
- is(value, 0)
-
- *tmp0 = 1
-
- value, _ = vm.ToValue(&tmp2)
- is(value, 1)
-
- tmp0 = nil
-
- value, _ = vm.ToValue(&tmp2)
- is(value, "undefined")
- }
- })
-}
-
-func TestToBoolean(t *testing.T) {
- tt(t, func() {
- is := func(left interface{}, right bool) {
- is(toValue(left).bool(), right)
- }
-
- is("", false)
- is("xyzzy", true)
- is(1, true)
- is(0, false)
- //is(toValue(newObject()), true)
- is(UndefinedValue(), false)
- is(NullValue(), false)
- })
-}
-
-func TestToFloat(t *testing.T) {
- tt(t, func() {
- {
- is := func(left interface{}, right float64) {
- is(toValue(left).float64(), right)
- }
- is("", 0)
- is("xyzzy", math.NaN())
- is("2", 2)
- is(1, 1)
- is(0, 0)
- is(NullValue(), 0)
- //is(newObjectValue(), math.NaN())
- }
- is(math.IsNaN(UndefinedValue().float64()), true)
- })
-}
-
-func TestToString(t *testing.T) {
- tt(t, func() {
- is("undefined", UndefinedValue().string())
- is("null", NullValue().string())
- is("true", toValue(true).string())
- is("false", toValue(false).string())
-
- is(UndefinedValue(), "undefined")
- is(NullValue(), "null")
- is(toValue(true), true)
- is(toValue(false), false)
- })
-}
-
-func Test_toInt32(t *testing.T) {
- tt(t, func() {
- test := []interface{}{
- 0, int32(0),
- 1, int32(1),
- -2147483649.0, int32(2147483647),
- -4294967297.0, int32(-1),
- -4294967296.0, int32(0),
- -4294967295.0, int32(1),
- math.Inf(+1), int32(0),
- math.Inf(-1), int32(0),
- }
- for index := 0; index < len(test)/2; index++ {
- // FIXME terst, Make strict again?
- is(
- toInt32(toValue(test[index*2])),
- test[index*2+1].(int32),
- )
- }
- })
-}
-
-func Test_toUint32(t *testing.T) {
- tt(t, func() {
- test := []interface{}{
- 0, uint32(0),
- 1, uint32(1),
- -2147483649.0, uint32(2147483647),
- -4294967297.0, uint32(4294967295),
- -4294967296.0, uint32(0),
- -4294967295.0, uint32(1),
- math.Inf(+1), uint32(0),
- math.Inf(-1), uint32(0),
- }
- for index := 0; index < len(test)/2; index++ {
- // FIXME terst, Make strict again?
- is(
- toUint32(toValue(test[index*2])),
- test[index*2+1].(uint32),
- )
- }
- })
-}
-
-func Test_toUint16(t *testing.T) {
- tt(t, func() {
- test := []interface{}{
- 0, uint16(0),
- 1, uint16(1),
- -2147483649.0, uint16(65535),
- -4294967297.0, uint16(65535),
- -4294967296.0, uint16(0),
- -4294967295.0, uint16(1),
- math.Inf(+1), uint16(0),
- math.Inf(-1), uint16(0),
- }
- for index := 0; index < len(test)/2; index++ {
- // FIXME terst, Make strict again?
- is(
- toUint16(toValue(test[index*2])),
- test[index*2+1].(uint16),
- )
- }
- })
-}
-
-func Test_sameValue(t *testing.T) {
- tt(t, func() {
- is(sameValue(positiveZeroValue(), negativeZeroValue()), false)
- is(sameValue(positiveZeroValue(), toValue(0)), true)
- is(sameValue(NaNValue(), NaNValue()), true)
- is(sameValue(NaNValue(), toValue("Nothing happens.")), false)
- })
-}
-
-func TestExport(t *testing.T) {
- tt(t, func() {
- test, vm := test()
-
- is(test(`null;`).export(), nil)
- is(test(`undefined;`).export(), nil)
- is(test(`true;`).export(), true)
- is(test(`false;`).export(), false)
- is(test(`0;`).export(), 0)
- is(test(`3.1459`).export(), 3.1459)
- is(test(`"Nothing happens";`).export(), "Nothing happens")
- is(test(`String.fromCharCode(97,98,99,100,101,102)`).export(), "abcdef")
- {
- value := test(`({ abc: 1, def: true, ghi: undefined });`).export().(map[string]interface{})
- is(value["abc"], 1)
- is(value["def"], true)
- _, exists := value["ghi"]
- is(exists, false)
- }
- {
- value := test(`[ "abc", 1, "def", true, undefined, null ];`).export().([]interface{})
- is(value[0], "abc")
- is(value[1], 1)
- is(value[2], "def")
- is(value[3], true)
- is(value[4], nil)
- is(value[5], nil)
- is(value[5], interface{}(nil))
- }
-
- roundtrip := []interface{}{
- true,
- false,
- 0,
- 3.1459,
- []interface{}{true, false, 0, 3.1459, "abc"},
- map[string]interface{}{
- "Boolean": true,
- "Number": 3.1459,
- "String": "abc",
- "Array": []interface{}{false, 0, "", nil},
- "Object": map[string]interface{}{
- "Boolean": false,
- "Number": 0,
- "String": "def",
- },
- },
- }
-
- for _, value := range roundtrip {
- input, err := json.Marshal(value)
- is(err, nil)
-
- output, err := json.Marshal(test("(" + string(input) + ");").export())
- is(err, nil)
-
- is(string(input), string(output))
- }
-
- {
- abc := struct {
- def int
- ghi interface{}
- xyz float32
- }{}
- abc.def = 3
- abc.xyz = 3.1459
- vm.Set("abc", abc)
- is(test(`abc;`).export(), abc)
- }
- })
-}
diff --git a/Godeps/_workspace/src/github.com/shiena/ansicolor/.gitignore b/Godeps/_workspace/src/github.com/shiena/ansicolor/.gitignore
deleted file mode 100644
index 69cec52c4..000000000
--- a/Godeps/_workspace/src/github.com/shiena/ansicolor/.gitignore
+++ /dev/null
@@ -1,27 +0,0 @@
-# Created by http://www.gitignore.io
-
-### Go ###
-# Compiled Object files, Static and Dynamic libs (Shared Objects)
-*.o
-*.a
-*.so
-
-# Folders
-_obj
-_test
-
-# Architecture specific extensions/prefixes
-*.[568vq]
-[568vq].out
-
-*.cgo1.go
-*.cgo2.c
-_cgo_defun.c
-_cgo_gotypes.go
-_cgo_export.*
-
-_testmain.go
-
-*.exe
-*.test
-
diff --git a/Godeps/_workspace/src/github.com/shiena/ansicolor/README.md b/Godeps/_workspace/src/github.com/shiena/ansicolor/README.md
deleted file mode 100644
index 7797a4f18..000000000
--- a/Godeps/_workspace/src/github.com/shiena/ansicolor/README.md
+++ /dev/null
@@ -1,100 +0,0 @@
-[![GoDoc](https://godoc.org/github.com/shiena/ansicolor?status.svg)](https://godoc.org/github.com/shiena/ansicolor)
-
-# ansicolor
-
-Ansicolor library provides color console in Windows as ANSICON for Golang.
-
-## Features
-
-|Escape sequence|Text attributes|
-|---------------|----|
-|\x1b[0m|All attributes off(color at startup)|
-|\x1b[1m|Bold on(enable foreground intensity)|
-|\x1b[4m|Underline on|
-|\x1b[5m|Blink on(enable background intensity)|
-|\x1b[21m|Bold off(disable foreground intensity)|
-|\x1b[24m|Underline off|
-|\x1b[25m|Blink off(disable background intensity)|
-
-|Escape sequence|Foreground colors|
-|---------------|----|
-|\x1b[30m|Black|
-|\x1b[31m|Red|
-|\x1b[32m|Green|
-|\x1b[33m|Yellow|
-|\x1b[34m|Blue|
-|\x1b[35m|Magenta|
-|\x1b[36m|Cyan|
-|\x1b[37m|White|
-|\x1b[39m|Default(foreground color at startup)|
-|\x1b[90m|Light Gray|
-|\x1b[91m|Light Red|
-|\x1b[92m|Light Green|
-|\x1b[93m|Light Yellow|
-|\x1b[94m|Light Blue|
-|\x1b[95m|Light Magenta|
-|\x1b[96m|Light Cyan|
-|\x1b[97m|Light White|
-
-|Escape sequence|Background colors|
-|---------------|----|
-|\x1b[40m|Black|
-|\x1b[41m|Red|
-|\x1b[42m|Green|
-|\x1b[43m|Yellow|
-|\x1b[44m|Blue|
-|\x1b[45m|Magenta|
-|\x1b[46m|Cyan|
-|\x1b[47m|White|
-|\x1b[49m|Default(background color at startup)|
-|\x1b[100m|Light Gray|
-|\x1b[101m|Light Red|
-|\x1b[102m|Light Green|
-|\x1b[103m|Light Yellow|
-|\x1b[104m|Light Blue|
-|\x1b[105m|Light Magenta|
-|\x1b[106m|Light Cyan|
-|\x1b[107m|Light White|
-
-## Example
-
-```go
-package main
-
-import (
- "fmt"
- "os"
-
- "github.com/shiena/ansicolor"
-)
-
-func main() {
- w := ansicolor.NewAnsiColorWriter(os.Stdout)
- text := "%sforeground %sbold%s %sbackground%s\n"
- fmt.Fprintf(w, text, "\x1b[31m", "\x1b[1m", "\x1b[21m", "\x1b[41;32m", "\x1b[0m")
- fmt.Fprintf(w, text, "\x1b[32m", "\x1b[1m", "\x1b[21m", "\x1b[42;31m", "\x1b[0m")
- fmt.Fprintf(w, text, "\x1b[33m", "\x1b[1m", "\x1b[21m", "\x1b[43;34m", "\x1b[0m")
- fmt.Fprintf(w, text, "\x1b[34m", "\x1b[1m", "\x1b[21m", "\x1b[44;33m", "\x1b[0m")
- fmt.Fprintf(w, text, "\x1b[35m", "\x1b[1m", "\x1b[21m", "\x1b[45;36m", "\x1b[0m")
- fmt.Fprintf(w, text, "\x1b[36m", "\x1b[1m", "\x1b[21m", "\x1b[46;35m", "\x1b[0m")
- fmt.Fprintf(w, text, "\x1b[37m", "\x1b[1m", "\x1b[21m", "\x1b[47;30m", "\x1b[0m")
-}
-```
-
-![screenshot](https://gist.githubusercontent.com/shiena/a1bada24b525314a7d5e/raw/c763aa7cda6e4fefaccf831e2617adc40b6151c7/main.png)
-
-## See also:
-
-- https://github.com/daviddengcn/go-colortext
-- https://github.com/adoxa/ansicon
-- https://github.com/aslakhellesoy/wac
-- https://github.com/wsxiaoys/terminal
-
-## Contributing
-
-1. Fork it
-2. Create your feature branch (`git checkout -b my-new-feature`)
-3. Commit your changes (`git commit -am 'Add some feature'`)
-4. Push to the branch (`git push origin my-new-feature`)
-5. Create new Pull Request
-
diff --git a/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor.go b/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor.go
deleted file mode 100644
index d3ece8fc0..000000000
--- a/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor.go
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2014 shiena Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-// Package ansicolor provides color console in Windows as ANSICON.
-package ansicolor
-
-import "io"
-
-// NewAnsiColorWriter creates and initializes a new ansiColorWriter
-// using io.Writer w as its initial contents.
-// In the console of Windows, which change the foreground and background
-// colors of the text by the escape sequence.
-// In the console of other systems, which writes to w all text.
-func NewAnsiColorWriter(w io.Writer) io.Writer {
- if _, ok := w.(*ansiColorWriter); !ok {
- return &ansiColorWriter{w: w}
- }
- return w
-}
diff --git a/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor/main.go b/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor/main.go
deleted file mode 100644
index d86cfc0f3..000000000
--- a/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor/main.go
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2014 shiena Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-/*
-
-The ansicolor command colors a console text by ANSI escape sequence like wac.
-
- $ go get github.com/shiena/ansicolor/ansicolor
-
-See also:
- https://github.com/aslakhellesoy/wac
-
-*/
-package main
-
-import (
- "io"
- "os"
-
- "github.com/shiena/ansicolor"
-)
-
-func main() {
- w := ansicolor.NewAnsiColorWriter(os.Stdout)
- io.Copy(w, os.Stdin)
-}
diff --git a/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_ansi.go b/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_ansi.go
deleted file mode 100644
index 57b4633a7..000000000
--- a/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_ansi.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2014 shiena Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-// +build !windows
-
-package ansicolor
-
-import "io"
-
-type ansiColorWriter struct {
- w io.Writer
-}
-
-func (cw *ansiColorWriter) Write(p []byte) (int, error) {
- return cw.w.Write(p)
-}
diff --git a/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_test.go b/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_test.go
deleted file mode 100644
index 4feeb1de6..000000000
--- a/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_test.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package ansicolor_test
-
-import (
- "bytes"
- "testing"
-
- "github.com/shiena/ansicolor"
-)
-
-func TestNewAnsiColor1(t *testing.T) {
- inner := bytes.NewBufferString("")
- w := ansicolor.NewAnsiColorWriter(inner)
- if w == inner {
- t.Errorf("Get %#v, want %#v", w, inner)
- }
-}
-
-func TestNewAnsiColor2(t *testing.T) {
- inner := bytes.NewBufferString("")
- w1 := ansicolor.NewAnsiColorWriter(inner)
- w2 := ansicolor.NewAnsiColorWriter(w1)
- if w1 != w2 {
- t.Errorf("Get %#v, want %#v", w1, w2)
- }
-}
diff --git a/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_windows.go b/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_windows.go
deleted file mode 100644
index d918ffe91..000000000
--- a/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_windows.go
+++ /dev/null
@@ -1,351 +0,0 @@
-// Copyright 2014 shiena Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-// +build windows
-
-package ansicolor
-
-import (
- "bytes"
- "io"
- "strings"
- "syscall"
- "unsafe"
-)
-
-type csiState int
-
-const (
- outsideCsiCode csiState = iota
- firstCsiCode
- secondCsiCode
-)
-
-type ansiColorWriter struct {
- w io.Writer
- state csiState
- paramBuf bytes.Buffer
-}
-
-const (
- firstCsiChar byte = '\x1b'
- secondeCsiChar byte = '['
- separatorChar byte = ';'
- sgrCode byte = 'm'
-)
-
-const (
- foregroundBlue = uint16(0x0001)
- foregroundGreen = uint16(0x0002)
- foregroundRed = uint16(0x0004)
- foregroundIntensity = uint16(0x0008)
- backgroundBlue = uint16(0x0010)
- backgroundGreen = uint16(0x0020)
- backgroundRed = uint16(0x0040)
- backgroundIntensity = uint16(0x0080)
- underscore = uint16(0x8000)
-
- foregroundMask = foregroundBlue | foregroundGreen | foregroundRed | foregroundIntensity
- backgroundMask = backgroundBlue | backgroundGreen | backgroundRed | backgroundIntensity
-)
-
-const (
- ansiReset = "0"
- ansiIntensityOn = "1"
- ansiIntensityOff = "21"
- ansiUnderlineOn = "4"
- ansiUnderlineOff = "24"
- ansiBlinkOn = "5"
- ansiBlinkOff = "25"
-
- ansiForegroundBlack = "30"
- ansiForegroundRed = "31"
- ansiForegroundGreen = "32"
- ansiForegroundYellow = "33"
- ansiForegroundBlue = "34"
- ansiForegroundMagenta = "35"
- ansiForegroundCyan = "36"
- ansiForegroundWhite = "37"
- ansiForegroundDefault = "39"
-
- ansiBackgroundBlack = "40"
- ansiBackgroundRed = "41"
- ansiBackgroundGreen = "42"
- ansiBackgroundYellow = "43"
- ansiBackgroundBlue = "44"
- ansiBackgroundMagenta = "45"
- ansiBackgroundCyan = "46"
- ansiBackgroundWhite = "47"
- ansiBackgroundDefault = "49"
-
- ansiLightForegroundGray = "90"
- ansiLightForegroundRed = "91"
- ansiLightForegroundGreen = "92"
- ansiLightForegroundYellow = "93"
- ansiLightForegroundBlue = "94"
- ansiLightForegroundMagenta = "95"
- ansiLightForegroundCyan = "96"
- ansiLightForegroundWhite = "97"
-
- ansiLightBackgroundGray = "100"
- ansiLightBackgroundRed = "101"
- ansiLightBackgroundGreen = "102"
- ansiLightBackgroundYellow = "103"
- ansiLightBackgroundBlue = "104"
- ansiLightBackgroundMagenta = "105"
- ansiLightBackgroundCyan = "106"
- ansiLightBackgroundWhite = "107"
-)
-
-type drawType int
-
-const (
- foreground drawType = iota
- background
-)
-
-type winColor struct {
- code uint16
- drawType drawType
-}
-
-var colorMap = map[string]winColor{
- ansiForegroundBlack: {0, foreground},
- ansiForegroundRed: {foregroundRed, foreground},
- ansiForegroundGreen: {foregroundGreen, foreground},
- ansiForegroundYellow: {foregroundRed | foregroundGreen, foreground},
- ansiForegroundBlue: {foregroundBlue, foreground},
- ansiForegroundMagenta: {foregroundRed | foregroundBlue, foreground},
- ansiForegroundCyan: {foregroundGreen | foregroundBlue, foreground},
- ansiForegroundWhite: {foregroundRed | foregroundGreen | foregroundBlue, foreground},
- ansiForegroundDefault: {foregroundRed | foregroundGreen | foregroundBlue, foreground},
-
- ansiBackgroundBlack: {0, background},
- ansiBackgroundRed: {backgroundRed, background},
- ansiBackgroundGreen: {backgroundGreen, background},
- ansiBackgroundYellow: {backgroundRed | backgroundGreen, background},
- ansiBackgroundBlue: {backgroundBlue, background},
- ansiBackgroundMagenta: {backgroundRed | backgroundBlue, background},
- ansiBackgroundCyan: {backgroundGreen | backgroundBlue, background},
- ansiBackgroundWhite: {backgroundRed | backgroundGreen | backgroundBlue, background},
- ansiBackgroundDefault: {0, background},
-
- ansiLightForegroundGray: {foregroundIntensity, foreground},
- ansiLightForegroundRed: {foregroundIntensity | foregroundRed, foreground},
- ansiLightForegroundGreen: {foregroundIntensity | foregroundGreen, foreground},
- ansiLightForegroundYellow: {foregroundIntensity | foregroundRed | foregroundGreen, foreground},
- ansiLightForegroundBlue: {foregroundIntensity | foregroundBlue, foreground},
- ansiLightForegroundMagenta: {foregroundIntensity | foregroundRed | foregroundBlue, foreground},
- ansiLightForegroundCyan: {foregroundIntensity | foregroundGreen | foregroundBlue, foreground},
- ansiLightForegroundWhite: {foregroundIntensity | foregroundRed | foregroundGreen | foregroundBlue, foreground},
-
- ansiLightBackgroundGray: {backgroundIntensity, background},
- ansiLightBackgroundRed: {backgroundIntensity | backgroundRed, background},
- ansiLightBackgroundGreen: {backgroundIntensity | backgroundGreen, background},
- ansiLightBackgroundYellow: {backgroundIntensity | backgroundRed | backgroundGreen, background},
- ansiLightBackgroundBlue: {backgroundIntensity | backgroundBlue, background},
- ansiLightBackgroundMagenta: {backgroundIntensity | backgroundRed | backgroundBlue, background},
- ansiLightBackgroundCyan: {backgroundIntensity | backgroundGreen | backgroundBlue, background},
- ansiLightBackgroundWhite: {backgroundIntensity | backgroundRed | backgroundGreen | backgroundBlue, background},
-}
-
-var (
- kernel32 = syscall.NewLazyDLL("kernel32.dll")
- procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute")
- procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
- defaultAttr *textAttributes
-)
-
-func init() {
- screenInfo := getConsoleScreenBufferInfo(uintptr(syscall.Stdout))
- if screenInfo != nil {
- colorMap[ansiForegroundDefault] = winColor{
- screenInfo.WAttributes & (foregroundRed | foregroundGreen | foregroundBlue),
- foreground,
- }
- colorMap[ansiBackgroundDefault] = winColor{
- screenInfo.WAttributes & (backgroundRed | backgroundGreen | backgroundBlue),
- background,
- }
- defaultAttr = convertTextAttr(screenInfo.WAttributes)
- }
-}
-
-type coord struct {
- X, Y int16
-}
-
-type smallRect struct {
- Left, Top, Right, Bottom int16
-}
-
-type consoleScreenBufferInfo struct {
- DwSize coord
- DwCursorPosition coord
- WAttributes uint16
- SrWindow smallRect
- DwMaximumWindowSize coord
-}
-
-func getConsoleScreenBufferInfo(hConsoleOutput uintptr) *consoleScreenBufferInfo {
- var csbi consoleScreenBufferInfo
- ret, _, _ := procGetConsoleScreenBufferInfo.Call(
- hConsoleOutput,
- uintptr(unsafe.Pointer(&csbi)))
- if ret == 0 {
- return nil
- }
- return &csbi
-}
-
-func setConsoleTextAttribute(hConsoleOutput uintptr, wAttributes uint16) bool {
- ret, _, _ := procSetConsoleTextAttribute.Call(
- hConsoleOutput,
- uintptr(wAttributes))
- return ret != 0
-}
-
-type textAttributes struct {
- foregroundColor uint16
- backgroundColor uint16
- foregroundIntensity uint16
- backgroundIntensity uint16
- underscore uint16
- otherAttributes uint16
-}
-
-func convertTextAttr(winAttr uint16) *textAttributes {
- fgColor := winAttr & (foregroundRed | foregroundGreen | foregroundBlue)
- bgColor := winAttr & (backgroundRed | backgroundGreen | backgroundBlue)
- fgIntensity := winAttr & foregroundIntensity
- bgIntensity := winAttr & backgroundIntensity
- underline := winAttr & underscore
- otherAttributes := winAttr &^ (foregroundMask | backgroundMask | underscore)
- return &textAttributes{fgColor, bgColor, fgIntensity, bgIntensity, underline, otherAttributes}
-}
-
-func convertWinAttr(textAttr *textAttributes) uint16 {
- var winAttr uint16 = 0
- winAttr |= textAttr.foregroundColor
- winAttr |= textAttr.backgroundColor
- winAttr |= textAttr.foregroundIntensity
- winAttr |= textAttr.backgroundIntensity
- winAttr |= textAttr.underscore
- winAttr |= textAttr.otherAttributes
- return winAttr
-}
-
-func changeColor(param []byte) {
- if defaultAttr == nil {
- return
- }
-
- screenInfo := getConsoleScreenBufferInfo(uintptr(syscall.Stdout))
- if screenInfo == nil {
- return
- }
-
- winAttr := convertTextAttr(screenInfo.WAttributes)
- strParam := string(param)
- if len(strParam) <= 0 {
- strParam = "0"
- }
- csiParam := strings.Split(strParam, string(separatorChar))
- for _, p := range csiParam {
- c, ok := colorMap[p]
- switch {
- case !ok:
- switch p {
- case ansiReset:
- winAttr.foregroundColor = defaultAttr.foregroundColor
- winAttr.backgroundColor = defaultAttr.backgroundColor
- winAttr.foregroundIntensity = defaultAttr.foregroundIntensity
- winAttr.backgroundIntensity = defaultAttr.backgroundIntensity
- winAttr.underscore = 0
- winAttr.otherAttributes = 0
- case ansiIntensityOn:
- winAttr.foregroundIntensity = foregroundIntensity
- case ansiIntensityOff:
- winAttr.foregroundIntensity = 0
- case ansiUnderlineOn:
- winAttr.underscore = underscore
- case ansiUnderlineOff:
- winAttr.underscore = 0
- case ansiBlinkOn:
- winAttr.backgroundIntensity = backgroundIntensity
- case ansiBlinkOff:
- winAttr.backgroundIntensity = 0
- default:
- // unknown code
- }
- case c.drawType == foreground:
- winAttr.foregroundColor = c.code
- case c.drawType == background:
- winAttr.backgroundColor = c.code
- }
- }
- winTextAttribute := convertWinAttr(winAttr)
- setConsoleTextAttribute(uintptr(syscall.Stdout), winTextAttribute)
-}
-
-func parseEscapeSequence(command byte, param []byte) {
- switch command {
- case sgrCode:
- changeColor(param)
- }
-}
-
-func isParameterChar(b byte) bool {
- return ('0' <= b && b <= '9') || b == separatorChar
-}
-
-func (cw *ansiColorWriter) Write(p []byte) (int, error) {
- r, nw, nc, first, last := 0, 0, 0, 0, 0
- var err error
- for i, ch := range p {
- switch cw.state {
- case outsideCsiCode:
- if ch == firstCsiChar {
- nc++
- cw.state = firstCsiCode
- }
- case firstCsiCode:
- switch ch {
- case firstCsiChar:
- nc++
- break
- case secondeCsiChar:
- nc++
- cw.state = secondCsiCode
- last = i - 1
- default:
- cw.state = outsideCsiCode
- }
- case secondCsiCode:
- nc++
- if isParameterChar(ch) {
- cw.paramBuf.WriteByte(ch)
- } else {
- nw, err = cw.w.Write(p[first:last])
- r += nw
- if err != nil {
- return r, err
- }
- first = i + 1
- param := cw.paramBuf.Bytes()
- cw.paramBuf.Reset()
- parseEscapeSequence(ch, param)
- cw.state = outsideCsiCode
- }
- default:
- cw.state = outsideCsiCode
- }
- }
-
- if cw.state == outsideCsiCode {
- nw, err = cw.w.Write(p[first:len(p)])
- }
-
- return r + nw + nc, err
-}
diff --git a/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_windows_test.go b/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_windows_test.go
deleted file mode 100644
index 6c126d517..000000000
--- a/Godeps/_workspace/src/github.com/shiena/ansicolor/ansicolor_windows_test.go
+++ /dev/null
@@ -1,236 +0,0 @@
-// Copyright 2014 shiena Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-// +build windows
-
-package ansicolor_test
-
-import (
- "bytes"
- "fmt"
- "syscall"
- "testing"
-
- "github.com/shiena/ansicolor"
- . "github.com/shiena/ansicolor"
-)
-
-func TestWritePlanText(t *testing.T) {
- inner := bytes.NewBufferString("")
- w := ansicolor.NewAnsiColorWriter(inner)
- expected := "plain text"
- fmt.Fprintf(w, expected)
- actual := inner.String()
- if actual != expected {
- t.Errorf("Get %s, want %s", actual, expected)
- }
-}
-
-func TestWriteParseText(t *testing.T) {
- inner := bytes.NewBufferString("")
- w := ansicolor.NewAnsiColorWriter(inner)
-
- inputTail := "\x1b[0mtail text"
- expectedTail := "tail text"
- fmt.Fprintf(w, inputTail)
- actualTail := inner.String()
- inner.Reset()
- if actualTail != expectedTail {
- t.Errorf("Get %s, want %s", actualTail, expectedTail)
- }
-
- inputHead := "head text\x1b[0m"
- expectedHead := "head text"
- fmt.Fprintf(w, inputHead)
- actualHead := inner.String()
- inner.Reset()
- if actualHead != expectedHead {
- t.Errorf("Get %s, want %s", actualHead, expectedHead)
- }
-
- inputBothEnds := "both ends \x1b[0m text"
- expectedBothEnds := "both ends text"
- fmt.Fprintf(w, inputBothEnds)
- actualBothEnds := inner.String()
- inner.Reset()
- if actualBothEnds != expectedBothEnds {
- t.Errorf("Get %s, want %s", actualBothEnds, expectedBothEnds)
- }
-
- inputManyEsc := "\x1b\x1b\x1b\x1b[0m many esc"
- expectedManyEsc := "\x1b\x1b\x1b many esc"
- fmt.Fprintf(w, inputManyEsc)
- actualManyEsc := inner.String()
- inner.Reset()
- if actualManyEsc != expectedManyEsc {
- t.Errorf("Get %s, want %s", actualManyEsc, expectedManyEsc)
- }
-
- expectedSplit := "split text"
- for _, ch := range "split \x1b[0m text" {
- fmt.Fprintf(w, string(ch))
- }
- actualSplit := inner.String()
- inner.Reset()
- if actualSplit != expectedSplit {
- t.Errorf("Get %s, want %s", actualSplit, expectedSplit)
- }
-}
-
-type screenNotFoundError struct {
- error
-}
-
-func writeAnsiColor(expectedText, colorCode string) (actualText string, actualAttributes uint16, err error) {
- inner := bytes.NewBufferString("")
- w := ansicolor.NewAnsiColorWriter(inner)
- fmt.Fprintf(w, "\x1b[%sm%s", colorCode, expectedText)
-
- actualText = inner.String()
- screenInfo := GetConsoleScreenBufferInfo(uintptr(syscall.Stdout))
- if screenInfo != nil {
- actualAttributes = screenInfo.WAttributes
- } else {
- err = &screenNotFoundError{}
- }
- return
-}
-
-type testParam struct {
- text string
- attributes uint16
- ansiColor string
-}
-
-func TestWriteAnsiColorText(t *testing.T) {
- screenInfo := GetConsoleScreenBufferInfo(uintptr(syscall.Stdout))
- if screenInfo == nil {
- t.Fatal("Could not get ConsoleScreenBufferInfo")
- }
- defer ChangeColor(screenInfo.WAttributes)
- defaultFgColor := screenInfo.WAttributes & uint16(0x0007)
- defaultBgColor := screenInfo.WAttributes & uint16(0x0070)
- defaultFgIntensity := screenInfo.WAttributes & uint16(0x0008)
- defaultBgIntensity := screenInfo.WAttributes & uint16(0x0080)
-
- fgParam := []testParam{
- {"foreground black ", uint16(0x0000 | 0x0000), "30"},
- {"foreground red ", uint16(0x0004 | 0x0000), "31"},
- {"foreground green ", uint16(0x0002 | 0x0000), "32"},
- {"foreground yellow ", uint16(0x0006 | 0x0000), "33"},
- {"foreground blue ", uint16(0x0001 | 0x0000), "34"},
- {"foreground magenta", uint16(0x0005 | 0x0000), "35"},
- {"foreground cyan ", uint16(0x0003 | 0x0000), "36"},
- {"foreground white ", uint16(0x0007 | 0x0000), "37"},
- {"foreground default", defaultFgColor | 0x0000, "39"},
- {"foreground light gray ", uint16(0x0000 | 0x0008 | 0x0000), "90"},
- {"foreground light red ", uint16(0x0004 | 0x0008 | 0x0000), "91"},
- {"foreground light green ", uint16(0x0002 | 0x0008 | 0x0000), "92"},
- {"foreground light yellow ", uint16(0x0006 | 0x0008 | 0x0000), "93"},
- {"foreground light blue ", uint16(0x0001 | 0x0008 | 0x0000), "94"},
- {"foreground light magenta", uint16(0x0005 | 0x0008 | 0x0000), "95"},
- {"foreground light cyan ", uint16(0x0003 | 0x0008 | 0x0000), "96"},
- {"foreground light white ", uint16(0x0007 | 0x0008 | 0x0000), "97"},
- }
-
- bgParam := []testParam{
- {"background black ", uint16(0x0007 | 0x0000), "40"},
- {"background red ", uint16(0x0007 | 0x0040), "41"},
- {"background green ", uint16(0x0007 | 0x0020), "42"},
- {"background yellow ", uint16(0x0007 | 0x0060), "43"},
- {"background blue ", uint16(0x0007 | 0x0010), "44"},
- {"background magenta", uint16(0x0007 | 0x0050), "45"},
- {"background cyan ", uint16(0x0007 | 0x0030), "46"},
- {"background white ", uint16(0x0007 | 0x0070), "47"},
- {"background default", uint16(0x0007) | defaultBgColor, "49"},
- {"background light gray ", uint16(0x0007 | 0x0000 | 0x0080), "100"},
- {"background light red ", uint16(0x0007 | 0x0040 | 0x0080), "101"},
- {"background light green ", uint16(0x0007 | 0x0020 | 0x0080), "102"},
- {"background light yellow ", uint16(0x0007 | 0x0060 | 0x0080), "103"},
- {"background light blue ", uint16(0x0007 | 0x0010 | 0x0080), "104"},
- {"background light magenta", uint16(0x0007 | 0x0050 | 0x0080), "105"},
- {"background light cyan ", uint16(0x0007 | 0x0030 | 0x0080), "106"},
- {"background light white ", uint16(0x0007 | 0x0070 | 0x0080), "107"},
- }
-
- resetParam := []testParam{
- {"all reset", defaultFgColor | defaultBgColor | defaultFgIntensity | defaultBgIntensity, "0"},
- {"all reset", defaultFgColor | defaultBgColor | defaultFgIntensity | defaultBgIntensity, ""},
- }
-
- boldParam := []testParam{
- {"bold on", uint16(0x0007 | 0x0008), "1"},
- {"bold off", uint16(0x0007), "21"},
- }
-
- underscoreParam := []testParam{
- {"underscore on", uint16(0x0007 | 0x8000), "4"},
- {"underscore off", uint16(0x0007), "24"},
- }
-
- blinkParam := []testParam{
- {"blink on", uint16(0x0007 | 0x0080), "5"},
- {"blink off", uint16(0x0007), "25"},
- }
-
- mixedParam := []testParam{
- {"both black, bold, underline, blink", uint16(0x0000 | 0x0000 | 0x0008 | 0x8000 | 0x0080), "30;40;1;4;5"},
- {"both red, bold, underline, blink", uint16(0x0004 | 0x0040 | 0x0008 | 0x8000 | 0x0080), "31;41;1;4;5"},
- {"both green, bold, underline, blink", uint16(0x0002 | 0x0020 | 0x0008 | 0x8000 | 0x0080), "32;42;1;4;5"},
- {"both yellow, bold, underline, blink", uint16(0x0006 | 0x0060 | 0x0008 | 0x8000 | 0x0080), "33;43;1;4;5"},
- {"both blue, bold, underline, blink", uint16(0x0001 | 0x0010 | 0x0008 | 0x8000 | 0x0080), "34;44;1;4;5"},
- {"both magenta, bold, underline, blink", uint16(0x0005 | 0x0050 | 0x0008 | 0x8000 | 0x0080), "35;45;1;4;5"},
- {"both cyan, bold, underline, blink", uint16(0x0003 | 0x0030 | 0x0008 | 0x8000 | 0x0080), "36;46;1;4;5"},
- {"both white, bold, underline, blink", uint16(0x0007 | 0x0070 | 0x0008 | 0x8000 | 0x0080), "37;47;1;4;5"},
- {"both default, bold, underline, blink", uint16(defaultFgColor | defaultBgColor | 0x0008 | 0x8000 | 0x0080), "39;49;1;4;5"},
- }
-
- assertTextAttribute := func(expectedText string, expectedAttributes uint16, ansiColor string) {
- actualText, actualAttributes, err := writeAnsiColor(expectedText, ansiColor)
- if actualText != expectedText {
- t.Errorf("Get %s, want %s", actualText, expectedText)
- }
- if err != nil {
- t.Fatal("Could not get ConsoleScreenBufferInfo")
- }
- if actualAttributes != expectedAttributes {
- t.Errorf("Text: %s, Get 0x%04x, want 0x%04x", expectedText, actualAttributes, expectedAttributes)
- }
- }
-
- for _, v := range fgParam {
- ResetColor()
- assertTextAttribute(v.text, v.attributes, v.ansiColor)
- }
-
- for _, v := range bgParam {
- ChangeColor(uint16(0x0070 | 0x0007))
- assertTextAttribute(v.text, v.attributes, v.ansiColor)
- }
-
- for _, v := range resetParam {
- ChangeColor(uint16(0x0000 | 0x0070 | 0x0008))
- assertTextAttribute(v.text, v.attributes, v.ansiColor)
- }
-
- ResetColor()
- for _, v := range boldParam {
- assertTextAttribute(v.text, v.attributes, v.ansiColor)
- }
-
- ResetColor()
- for _, v := range underscoreParam {
- assertTextAttribute(v.text, v.attributes, v.ansiColor)
- }
-
- ResetColor()
- for _, v := range blinkParam {
- assertTextAttribute(v.text, v.attributes, v.ansiColor)
- }
-
- for _, v := range mixedParam {
- ResetColor()
- assertTextAttribute(v.text, v.attributes, v.ansiColor)
- }
-}
diff --git a/Godeps/_workspace/src/github.com/shiena/ansicolor/example_test.go b/Godeps/_workspace/src/github.com/shiena/ansicolor/example_test.go
deleted file mode 100644
index f2ac67c17..000000000
--- a/Godeps/_workspace/src/github.com/shiena/ansicolor/example_test.go
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2014 shiena Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-package ansicolor_test
-
-import (
- "fmt"
- "os"
-
- "github.com/shiena/ansicolor"
-)
-
-func ExampleNewAnsiColorWriter() {
- w := ansicolor.NewAnsiColorWriter(os.Stdout)
- text := "%sforeground %sbold%s %sbackground%s\n"
- fmt.Fprintf(w, text, "\x1b[31m", "\x1b[1m", "\x1b[21m", "\x1b[41;32m", "\x1b[0m")
- fmt.Fprintf(w, text, "\x1b[32m", "\x1b[1m", "\x1b[21m", "\x1b[42;31m", "\x1b[0m")
- fmt.Fprintf(w, text, "\x1b[33m", "\x1b[1m", "\x1b[21m", "\x1b[43;34m", "\x1b[0m")
- fmt.Fprintf(w, text, "\x1b[34m", "\x1b[1m", "\x1b[21m", "\x1b[44;33m", "\x1b[0m")
- fmt.Fprintf(w, text, "\x1b[35m", "\x1b[1m", "\x1b[21m", "\x1b[45;36m", "\x1b[0m")
- fmt.Fprintf(w, text, "\x1b[36m", "\x1b[1m", "\x1b[21m", "\x1b[46;35m", "\x1b[0m")
- fmt.Fprintf(w, text, "\x1b[37m", "\x1b[1m", "\x1b[21m", "\x1b[47;30m", "\x1b[0m")
-}
diff --git a/Godeps/_workspace/src/github.com/shiena/ansicolor/export_test.go b/Godeps/_workspace/src/github.com/shiena/ansicolor/export_test.go
deleted file mode 100644
index 6d2f7c074..000000000
--- a/Godeps/_workspace/src/github.com/shiena/ansicolor/export_test.go
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2014 shiena Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-// +build windows
-
-package ansicolor
-
-import "syscall"
-
-var GetConsoleScreenBufferInfo = getConsoleScreenBufferInfo
-
-func ChangeColor(color uint16) {
- setConsoleTextAttribute(uintptr(syscall.Stdout), color)
-}
-
-func ResetColor() {
- ChangeColor(uint16(0x0007))
-}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/LICENSE b/Godeps/_workspace/src/github.com/syndtr/goleveldb/LICENSE
new file mode 100644
index 000000000..4a772d1ab
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/LICENSE
@@ -0,0 +1,24 @@
+Copyright 2012 Suryandaru Triandana <syndtr@gmail.com>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * 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.
+
+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.
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/batch.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/batch.go
index ccf390c9c..89fcf34bb 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/batch.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/batch.go
@@ -12,6 +12,7 @@ import (
"github.com/syndtr/goleveldb/leveldb/errors"
"github.com/syndtr/goleveldb/leveldb/memdb"
+ "github.com/syndtr/goleveldb/leveldb/storage"
)
type ErrBatchCorrupted struct {
@@ -23,7 +24,7 @@ func (e *ErrBatchCorrupted) Error() string {
}
func newErrBatchCorrupted(reason string) error {
- return errors.NewErrCorrupted(nil, &ErrBatchCorrupted{reason})
+ return errors.NewErrCorrupted(storage.FileDesc{}, &ErrBatchCorrupted{reason})
}
const (
@@ -121,13 +122,14 @@ func (b *Batch) Load(data []byte) error {
// Replay replays batch contents.
func (b *Batch) Replay(r BatchReplay) error {
- return b.decodeRec(func(i int, kt kType, key, value []byte) {
+ return b.decodeRec(func(i int, kt kType, key, value []byte) error {
switch kt {
case ktVal:
r.Put(key, value)
case ktDel:
r.Delete(key)
}
+ return nil
})
}
@@ -193,7 +195,7 @@ func (b *Batch) decode(prevSeq uint64, data []byte) error {
return nil
}
-func (b *Batch) decodeRec(f func(i int, kt kType, key, value []byte)) (err error) {
+func (b *Batch) decodeRec(f func(i int, kt kType, key, value []byte) error) error {
off := batchHdrLen
for i := 0; i < b.rLen; i++ {
if off >= len(b.data) {
@@ -224,16 +226,19 @@ func (b *Batch) decodeRec(f func(i int, kt kType, key, value []byte)) (err error
off += int(x)
}
- f(i, kt, key, value)
+ if err := f(i, kt, key, value); err != nil {
+ return err
+ }
}
return nil
}
func (b *Batch) memReplay(to *memdb.DB) error {
- return b.decodeRec(func(i int, kt kType, key, value []byte) {
- ikey := newIkey(key, b.seq+uint64(i), kt)
- to.Put(ikey, value)
+ var ikScratch []byte
+ return b.decodeRec(func(i int, kt kType, key, value []byte) error {
+ ikScratch = makeIkey(ikScratch, key, b.seq+uint64(i), kt)
+ return to.Put(ikScratch, value)
})
}
@@ -245,8 +250,9 @@ func (b *Batch) memDecodeAndReplay(prevSeq uint64, data []byte, to *memdb.DB) er
}
func (b *Batch) revertMemReplay(to *memdb.DB) error {
- return b.decodeRec(func(i int, kt kType, key, value []byte) {
- ikey := newIkey(key, b.seq+uint64(i), kt)
- to.Delete(ikey)
+ var ikScratch []byte
+ return b.decodeRec(func(i int, kt kType, key, value []byte) error {
+ ikScratch := makeIkey(ikScratch, key, b.seq+uint64(i), kt)
+ return to.Delete(ikScratch)
})
}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/batch_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/batch_test.go
deleted file mode 100644
index 7fc842f4f..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/batch_test.go
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
-// All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package leveldb
-
-import (
- "bytes"
- "testing"
-
- "github.com/syndtr/goleveldb/leveldb/comparer"
- "github.com/syndtr/goleveldb/leveldb/memdb"
-)
-
-type tbRec struct {
- kt kType
- key, value []byte
-}
-
-type testBatch struct {
- rec []*tbRec
-}
-
-func (p *testBatch) Put(key, value []byte) {
- p.rec = append(p.rec, &tbRec{ktVal, key, value})
-}
-
-func (p *testBatch) Delete(key []byte) {
- p.rec = append(p.rec, &tbRec{ktDel, key, nil})
-}
-
-func compareBatch(t *testing.T, b1, b2 *Batch) {
- if b1.seq != b2.seq {
- t.Errorf("invalid seq number want %d, got %d", b1.seq, b2.seq)
- }
- if b1.Len() != b2.Len() {
- t.Fatalf("invalid record length want %d, got %d", b1.Len(), b2.Len())
- }
- p1, p2 := new(testBatch), new(testBatch)
- err := b1.Replay(p1)
- if err != nil {
- t.Fatal("error when replaying batch 1: ", err)
- }
- err = b2.Replay(p2)
- if err != nil {
- t.Fatal("error when replaying batch 2: ", err)
- }
- for i := range p1.rec {
- r1, r2 := p1.rec[i], p2.rec[i]
- if r1.kt != r2.kt {
- t.Errorf("invalid type on record '%d' want %d, got %d", i, r1.kt, r2.kt)
- }
- if !bytes.Equal(r1.key, r2.key) {
- t.Errorf("invalid key on record '%d' want %s, got %s", i, string(r1.key), string(r2.key))
- }
- if r1.kt == ktVal {
- if !bytes.Equal(r1.value, r2.value) {
- t.Errorf("invalid value on record '%d' want %s, got %s", i, string(r1.value), string(r2.value))
- }
- }
- }
-}
-
-func TestBatch_EncodeDecode(t *testing.T) {
- b1 := new(Batch)
- b1.seq = 10009
- b1.Put([]byte("key1"), []byte("value1"))
- b1.Put([]byte("key2"), []byte("value2"))
- b1.Delete([]byte("key1"))
- b1.Put([]byte("k"), []byte(""))
- b1.Put([]byte("zzzzzzzzzzz"), []byte("zzzzzzzzzzzzzzzzzzzzzzzz"))
- b1.Delete([]byte("key10000"))
- b1.Delete([]byte("k"))
- buf := b1.encode()
- b2 := new(Batch)
- err := b2.decode(0, buf)
- if err != nil {
- t.Error("error when decoding batch: ", err)
- }
- compareBatch(t, b1, b2)
-}
-
-func TestBatch_Append(t *testing.T) {
- b1 := new(Batch)
- b1.seq = 10009
- b1.Put([]byte("key1"), []byte("value1"))
- b1.Put([]byte("key2"), []byte("value2"))
- b1.Delete([]byte("key1"))
- b1.Put([]byte("foo"), []byte("foovalue"))
- b1.Put([]byte("bar"), []byte("barvalue"))
- b2a := new(Batch)
- b2a.seq = 10009
- b2a.Put([]byte("key1"), []byte("value1"))
- b2a.Put([]byte("key2"), []byte("value2"))
- b2a.Delete([]byte("key1"))
- b2b := new(Batch)
- b2b.Put([]byte("foo"), []byte("foovalue"))
- b2b.Put([]byte("bar"), []byte("barvalue"))
- b2a.append(b2b)
- compareBatch(t, b1, b2a)
-}
-
-func TestBatch_Size(t *testing.T) {
- b := new(Batch)
- for i := 0; i < 2; i++ {
- b.Put([]byte("key1"), []byte("value1"))
- b.Put([]byte("key2"), []byte("value2"))
- b.Delete([]byte("key1"))
- b.Put([]byte("foo"), []byte("foovalue"))
- b.Put([]byte("bar"), []byte("barvalue"))
- mem := memdb.New(&iComparer{comparer.DefaultComparer}, 0)
- b.memReplay(mem)
- if b.size() != mem.Size() {
- t.Errorf("invalid batch size calculation, want=%d got=%d", mem.Size(), b.size())
- }
- b.Reset()
- }
-}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/bench2_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/bench2_test.go
deleted file mode 100644
index 0dd60fd82..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/bench2_test.go
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
-// All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// +build !go1.2
-
-package leveldb
-
-import (
- "sync/atomic"
- "testing"
-)
-
-func BenchmarkDBReadConcurrent(b *testing.B) {
- p := openDBBench(b, false)
- p.populate(b.N)
- p.fill()
- p.gc()
- defer p.close()
-
- b.ResetTimer()
- b.SetBytes(116)
-
- b.RunParallel(func(pb *testing.PB) {
- iter := p.newIter()
- defer iter.Release()
- for pb.Next() && iter.Next() {
- }
- })
-}
-
-func BenchmarkDBReadConcurrent2(b *testing.B) {
- p := openDBBench(b, false)
- p.populate(b.N)
- p.fill()
- p.gc()
- defer p.close()
-
- b.ResetTimer()
- b.SetBytes(116)
-
- var dir uint32
- b.RunParallel(func(pb *testing.PB) {
- iter := p.newIter()
- defer iter.Release()
- if atomic.AddUint32(&dir, 1)%2 == 0 {
- for pb.Next() && iter.Next() {
- }
- } else {
- if pb.Next() && iter.Last() {
- for pb.Next() && iter.Prev() {
- }
- }
- }
- })
-}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/bench_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/bench_test.go
deleted file mode 100644
index 91b426709..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/bench_test.go
+++ /dev/null
@@ -1,464 +0,0 @@
-// Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
-// All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package leveldb
-
-import (
- "bytes"
- "fmt"
- "math/rand"
- "os"
- "path/filepath"
- "runtime"
- "testing"
-
- "github.com/syndtr/goleveldb/leveldb/iterator"
- "github.com/syndtr/goleveldb/leveldb/opt"
- "github.com/syndtr/goleveldb/leveldb/storage"
-)
-
-func randomString(r *rand.Rand, n int) []byte {
- b := new(bytes.Buffer)
- for i := 0; i < n; i++ {
- b.WriteByte(' ' + byte(r.Intn(95)))
- }
- return b.Bytes()
-}
-
-func compressibleStr(r *rand.Rand, frac float32, n int) []byte {
- nn := int(float32(n) * frac)
- rb := randomString(r, nn)
- b := make([]byte, 0, n+nn)
- for len(b) < n {
- b = append(b, rb...)
- }
- return b[:n]
-}
-
-type valueGen struct {
- src []byte
- pos int
-}
-
-func newValueGen(frac float32) *valueGen {
- v := new(valueGen)
- r := rand.New(rand.NewSource(301))
- v.src = make([]byte, 0, 1048576+100)
- for len(v.src) < 1048576 {
- v.src = append(v.src, compressibleStr(r, frac, 100)...)
- }
- return v
-}
-
-func (v *valueGen) get(n int) []byte {
- if v.pos+n > len(v.src) {
- v.pos = 0
- }
- v.pos += n
- return v.src[v.pos-n : v.pos]
-}
-
-var benchDB = filepath.Join(os.TempDir(), fmt.Sprintf("goleveldbbench-%d", os.Getuid()))
-
-type dbBench struct {
- b *testing.B
- stor storage.Storage
- db *DB
-
- o *opt.Options
- ro *opt.ReadOptions
- wo *opt.WriteOptions
-
- keys, values [][]byte
-}
-
-func openDBBench(b *testing.B, noCompress bool) *dbBench {
- _, err := os.Stat(benchDB)
- if err == nil {
- err = os.RemoveAll(benchDB)
- if err != nil {
- b.Fatal("cannot remove old db: ", err)
- }
- }
-
- p := &dbBench{
- b: b,
- o: &opt.Options{},
- ro: &opt.ReadOptions{},
- wo: &opt.WriteOptions{},
- }
- p.stor, err = storage.OpenFile(benchDB)
- if err != nil {
- b.Fatal("cannot open stor: ", err)
- }
- if noCompress {
- p.o.Compression = opt.NoCompression
- }
-
- p.db, err = Open(p.stor, p.o)
- if err != nil {
- b.Fatal("cannot open db: ", err)
- }
-
- runtime.GOMAXPROCS(runtime.NumCPU())
- return p
-}
-
-func (p *dbBench) reopen() {
- p.db.Close()
- var err error
- p.db, err = Open(p.stor, p.o)
- if err != nil {
- p.b.Fatal("Reopen: got error: ", err)
- }
-}
-
-func (p *dbBench) populate(n int) {
- p.keys, p.values = make([][]byte, n), make([][]byte, n)
- v := newValueGen(0.5)
- for i := range p.keys {
- p.keys[i], p.values[i] = []byte(fmt.Sprintf("%016d", i)), v.get(100)
- }
-}
-
-func (p *dbBench) randomize() {
- m := len(p.keys)
- times := m * 2
- r1, r2 := rand.New(rand.NewSource(0xdeadbeef)), rand.New(rand.NewSource(0xbeefface))
- for n := 0; n < times; n++ {
- i, j := r1.Int()%m, r2.Int()%m
- if i == j {
- continue
- }
- p.keys[i], p.keys[j] = p.keys[j], p.keys[i]
- p.values[i], p.values[j] = p.values[j], p.values[i]
- }
-}
-
-func (p *dbBench) writes(perBatch int) {
- b := p.b
- db := p.db
-
- n := len(p.keys)
- m := n / perBatch
- if n%perBatch > 0 {
- m++
- }
- batches := make([]Batch, m)
- j := 0
- for i := range batches {
- first := true
- for ; j < n && ((j+1)%perBatch != 0 || first); j++ {
- first = false
- batches[i].Put(p.keys[j], p.values[j])
- }
- }
- runtime.GC()
-
- b.ResetTimer()
- b.StartTimer()
- for i := range batches {
- err := db.Write(&(batches[i]), p.wo)
- if err != nil {
- b.Fatal("write failed: ", err)
- }
- }
- b.StopTimer()
- b.SetBytes(116)
-}
-
-func (p *dbBench) gc() {
- p.keys, p.values = nil, nil
- runtime.GC()
-}
-
-func (p *dbBench) puts() {
- b := p.b
- db := p.db
-
- b.ResetTimer()
- b.StartTimer()
- for i := range p.keys {
- err := db.Put(p.keys[i], p.values[i], p.wo)
- if err != nil {
- b.Fatal("put failed: ", err)
- }
- }
- b.StopTimer()
- b.SetBytes(116)
-}
-
-func (p *dbBench) fill() {
- b := p.b
- db := p.db
-
- perBatch := 10000
- batch := new(Batch)
- for i, n := 0, len(p.keys); i < n; {
- first := true
- for ; i < n && ((i+1)%perBatch != 0 || first); i++ {
- first = false
- batch.Put(p.keys[i], p.values[i])
- }
- err := db.Write(batch, p.wo)
- if err != nil {
- b.Fatal("write failed: ", err)
- }
- batch.Reset()
- }
-}
-
-func (p *dbBench) gets() {
- b := p.b
- db := p.db
-
- b.ResetTimer()
- for i := range p.keys {
- _, err := db.Get(p.keys[i], p.ro)
- if err != nil {
- b.Error("got error: ", err)
- }
- }
- b.StopTimer()
-}
-
-func (p *dbBench) seeks() {
- b := p.b
-
- iter := p.newIter()
- defer iter.Release()
- b.ResetTimer()
- for i := range p.keys {
- if !iter.Seek(p.keys[i]) {
- b.Error("value not found for: ", string(p.keys[i]))
- }
- }
- b.StopTimer()
-}
-
-func (p *dbBench) newIter() iterator.Iterator {
- iter := p.db.NewIterator(nil, p.ro)
- err := iter.Error()
- if err != nil {
- p.b.Fatal("cannot create iterator: ", err)
- }
- return iter
-}
-
-func (p *dbBench) close() {
- if bp, err := p.db.GetProperty("leveldb.blockpool"); err == nil {
- p.b.Log("Block pool stats: ", bp)
- }
- p.db.Close()
- p.stor.Close()
- os.RemoveAll(benchDB)
- p.db = nil
- p.keys = nil
- p.values = nil
- runtime.GC()
- runtime.GOMAXPROCS(1)
-}
-
-func BenchmarkDBWrite(b *testing.B) {
- p := openDBBench(b, false)
- p.populate(b.N)
- p.writes(1)
- p.close()
-}
-
-func BenchmarkDBWriteBatch(b *testing.B) {
- p := openDBBench(b, false)
- p.populate(b.N)
- p.writes(1000)
- p.close()
-}
-
-func BenchmarkDBWriteUncompressed(b *testing.B) {
- p := openDBBench(b, true)
- p.populate(b.N)
- p.writes(1)
- p.close()
-}
-
-func BenchmarkDBWriteBatchUncompressed(b *testing.B) {
- p := openDBBench(b, true)
- p.populate(b.N)
- p.writes(1000)
- p.close()
-}
-
-func BenchmarkDBWriteRandom(b *testing.B) {
- p := openDBBench(b, false)
- p.populate(b.N)
- p.randomize()
- p.writes(1)
- p.close()
-}
-
-func BenchmarkDBWriteRandomSync(b *testing.B) {
- p := openDBBench(b, false)
- p.wo.Sync = true
- p.populate(b.N)
- p.writes(1)
- p.close()
-}
-
-func BenchmarkDBOverwrite(b *testing.B) {
- p := openDBBench(b, false)
- p.populate(b.N)
- p.writes(1)
- p.writes(1)
- p.close()
-}
-
-func BenchmarkDBOverwriteRandom(b *testing.B) {
- p := openDBBench(b, false)
- p.populate(b.N)
- p.writes(1)
- p.randomize()
- p.writes(1)
- p.close()
-}
-
-func BenchmarkDBPut(b *testing.B) {
- p := openDBBench(b, false)
- p.populate(b.N)
- p.puts()
- p.close()
-}
-
-func BenchmarkDBRead(b *testing.B) {
- p := openDBBench(b, false)
- p.populate(b.N)
- p.fill()
- p.gc()
-
- iter := p.newIter()
- b.ResetTimer()
- for iter.Next() {
- }
- iter.Release()
- b.StopTimer()
- b.SetBytes(116)
- p.close()
-}
-
-func BenchmarkDBReadGC(b *testing.B) {
- p := openDBBench(b, false)
- p.populate(b.N)
- p.fill()
-
- iter := p.newIter()
- b.ResetTimer()
- for iter.Next() {
- }
- iter.Release()
- b.StopTimer()
- b.SetBytes(116)
- p.close()
-}
-
-func BenchmarkDBReadUncompressed(b *testing.B) {
- p := openDBBench(b, true)
- p.populate(b.N)
- p.fill()
- p.gc()
-
- iter := p.newIter()
- b.ResetTimer()
- for iter.Next() {
- }
- iter.Release()
- b.StopTimer()
- b.SetBytes(116)
- p.close()
-}
-
-func BenchmarkDBReadTable(b *testing.B) {
- p := openDBBench(b, false)
- p.populate(b.N)
- p.fill()
- p.reopen()
- p.gc()
-
- iter := p.newIter()
- b.ResetTimer()
- for iter.Next() {
- }
- iter.Release()
- b.StopTimer()
- b.SetBytes(116)
- p.close()
-}
-
-func BenchmarkDBReadReverse(b *testing.B) {
- p := openDBBench(b, false)
- p.populate(b.N)
- p.fill()
- p.gc()
-
- iter := p.newIter()
- b.ResetTimer()
- iter.Last()
- for iter.Prev() {
- }
- iter.Release()
- b.StopTimer()
- b.SetBytes(116)
- p.close()
-}
-
-func BenchmarkDBReadReverseTable(b *testing.B) {
- p := openDBBench(b, false)
- p.populate(b.N)
- p.fill()
- p.reopen()
- p.gc()
-
- iter := p.newIter()
- b.ResetTimer()
- iter.Last()
- for iter.Prev() {
- }
- iter.Release()
- b.StopTimer()
- b.SetBytes(116)
- p.close()
-}
-
-func BenchmarkDBSeek(b *testing.B) {
- p := openDBBench(b, false)
- p.populate(b.N)
- p.fill()
- p.seeks()
- p.close()
-}
-
-func BenchmarkDBSeekRandom(b *testing.B) {
- p := openDBBench(b, false)
- p.populate(b.N)
- p.fill()
- p.randomize()
- p.seeks()
- p.close()
-}
-
-func BenchmarkDBGet(b *testing.B) {
- p := openDBBench(b, false)
- p.populate(b.N)
- p.fill()
- p.gets()
- p.close()
-}
-
-func BenchmarkDBGetRandom(b *testing.B) {
- p := openDBBench(b, false)
- p.populate(b.N)
- p.fill()
- p.randomize()
- p.gets()
- p.close()
-}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/bench2_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/bench2_test.go
deleted file mode 100644
index 175e22203..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/bench2_test.go
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
-// All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// +build !go1.2
-
-package cache
-
-import (
- "math/rand"
- "testing"
-)
-
-func BenchmarkLRUCache(b *testing.B) {
- c := NewCache(NewLRU(10000))
-
- b.SetParallelism(10)
- b.RunParallel(func(pb *testing.PB) {
- r := rand.New(rand.NewSource(time.Now().UnixNano()))
-
- for pb.Next() {
- key := uint64(r.Intn(1000000))
- c.Get(0, key, func() (int, Value) {
- return 1, key
- }).Release()
- }
- })
-}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/cache_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/cache_test.go
deleted file mode 100644
index c2a50156f..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache/cache_test.go
+++ /dev/null
@@ -1,554 +0,0 @@
-// Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
-// All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package cache
-
-import (
- "math/rand"
- "runtime"
- "sync"
- "sync/atomic"
- "testing"
- "time"
- "unsafe"
-)
-
-type int32o int32
-
-func (o *int32o) acquire() {
- if atomic.AddInt32((*int32)(o), 1) != 1 {
- panic("BUG: invalid ref")
- }
-}
-
-func (o *int32o) Release() {
- if atomic.AddInt32((*int32)(o), -1) != 0 {
- panic("BUG: invalid ref")
- }
-}
-
-type releaserFunc struct {
- fn func()
- value Value
-}
-
-func (r releaserFunc) Release() {
- if r.fn != nil {
- r.fn()
- }
-}
-
-func set(c *Cache, ns, key uint64, value Value, charge int, relf func()) *Handle {
- return c.Get(ns, key, func() (int, Value) {
- if relf != nil {
- return charge, releaserFunc{relf, value}
- } else {
- return charge, value
- }
- })
-}
-
-func TestCacheMap(t *testing.T) {
- runtime.GOMAXPROCS(runtime.NumCPU())
-
- nsx := []struct {
- nobjects, nhandles, concurrent, repeat int
- }{
- {10000, 400, 50, 3},
- {100000, 1000, 100, 10},
- }
-
- var (
- objects [][]int32o
- handles [][]unsafe.Pointer
- )
-
- for _, x := range nsx {
- objects = append(objects, make([]int32o, x.nobjects))
- handles = append(handles, make([]unsafe.Pointer, x.nhandles))
- }
-
- c := NewCache(nil)
-
- wg := new(sync.WaitGroup)
- var done int32
-
- for ns, x := range nsx {
- for i := 0; i < x.concurrent; i++ {
- wg.Add(1)
- go func(ns, i, repeat int, objects []int32o, handles []unsafe.Pointer) {
- defer wg.Done()
- r := rand.New(rand.NewSource(time.Now().UnixNano()))
-
- for j := len(objects) * repeat; j >= 0; j-- {
- key := uint64(r.Intn(len(objects)))
- h := c.Get(uint64(ns), key, func() (int, Value) {
- o := &objects[key]
- o.acquire()
- return 1, o
- })
- if v := h.Value().(*int32o); v != &objects[key] {
- t.Fatalf("#%d invalid value: want=%p got=%p", ns, &objects[key], v)
- }
- if objects[key] != 1 {
- t.Fatalf("#%d invalid object %d: %d", ns, key, objects[key])
- }
- if !atomic.CompareAndSwapPointer(&handles[r.Intn(len(handles))], nil, unsafe.Pointer(h)) {
- h.Release()
- }
- }
- }(ns, i, x.repeat, objects[ns], handles[ns])
- }
-
- go func(handles []unsafe.Pointer) {
- r := rand.New(rand.NewSource(time.Now().UnixNano()))
-
- for atomic.LoadInt32(&done) == 0 {
- i := r.Intn(len(handles))
- h := (*Handle)(atomic.LoadPointer(&handles[i]))
- if h != nil && atomic.CompareAndSwapPointer(&handles[i], unsafe.Pointer(h), nil) {
- h.Release()
- }
- time.Sleep(time.Millisecond)
- }
- }(handles[ns])
- }
-
- go func() {
- handles := make([]*Handle, 100000)
- for atomic.LoadInt32(&done) == 0 {
- for i := range handles {
- handles[i] = c.Get(999999999, uint64(i), func() (int, Value) {
- return 1, 1
- })
- }
- for _, h := range handles {
- h.Release()
- }
- }
- }()
-
- wg.Wait()
-
- atomic.StoreInt32(&done, 1)
-
- for _, handles0 := range handles {
- for i := range handles0 {
- h := (*Handle)(atomic.LoadPointer(&handles0[i]))
- if h != nil && atomic.CompareAndSwapPointer(&handles0[i], unsafe.Pointer(h), nil) {
- h.Release()
- }
- }
- }
-
- for ns, objects0 := range objects {
- for i, o := range objects0 {
- if o != 0 {
- t.Fatalf("invalid object #%d.%d: ref=%d", ns, i, o)
- }
- }
- }
-}
-
-func TestCacheMap_NodesAndSize(t *testing.T) {
- c := NewCache(nil)
- if c.Nodes() != 0 {
- t.Errorf("invalid nodes counter: want=%d got=%d", 0, c.Nodes())
- }
- if c.Size() != 0 {
- t.Errorf("invalid size counter: want=%d got=%d", 0, c.Size())
- }
- set(c, 0, 1, 1, 1, nil)
- set(c, 0, 2, 2, 2, nil)
- set(c, 1, 1, 3, 3, nil)
- set(c, 2, 1, 4, 1, nil)
- if c.Nodes() != 4 {
- t.Errorf("invalid nodes counter: want=%d got=%d", 4, c.Nodes())
- }
- if c.Size() != 7 {
- t.Errorf("invalid size counter: want=%d got=%d", 4, c.Size())
- }
-}
-
-func TestLRUCache_Capacity(t *testing.T) {
- c := NewCache(NewLRU(10))
- if c.Capacity() != 10 {
- t.Errorf("invalid capacity: want=%d got=%d", 10, c.Capacity())
- }
- set(c, 0, 1, 1, 1, nil).Release()
- set(c, 0, 2, 2, 2, nil).Release()
- set(c, 1, 1, 3, 3, nil).Release()
- set(c, 2, 1, 4, 1, nil).Release()
- set(c, 2, 2, 5, 1, nil).Release()
- set(c, 2, 3, 6, 1, nil).Release()
- set(c, 2, 4, 7, 1, nil).Release()
- set(c, 2, 5, 8, 1, nil).Release()
- if c.Nodes() != 7 {
- t.Errorf("invalid nodes counter: want=%d got=%d", 7, c.Nodes())
- }
- if c.Size() != 10 {
- t.Errorf("invalid size counter: want=%d got=%d", 10, c.Size())
- }
- c.SetCapacity(9)
- if c.Capacity() != 9 {
- t.Errorf("invalid capacity: want=%d got=%d", 9, c.Capacity())
- }
- if c.Nodes() != 6 {
- t.Errorf("invalid nodes counter: want=%d got=%d", 6, c.Nodes())
- }
- if c.Size() != 8 {
- t.Errorf("invalid size counter: want=%d got=%d", 8, c.Size())
- }
-}
-
-func TestCacheMap_NilValue(t *testing.T) {
- c := NewCache(NewLRU(10))
- h := c.Get(0, 0, func() (size int, value Value) {
- return 1, nil
- })
- if h != nil {
- t.Error("cache handle is non-nil")
- }
- if c.Nodes() != 0 {
- t.Errorf("invalid nodes counter: want=%d got=%d", 0, c.Nodes())
- }
- if c.Size() != 0 {
- t.Errorf("invalid size counter: want=%d got=%d", 0, c.Size())
- }
-}
-
-func TestLRUCache_GetLatency(t *testing.T) {
- runtime.GOMAXPROCS(runtime.NumCPU())
-
- const (
- concurrentSet = 30
- concurrentGet = 3
- duration = 3 * time.Second
- delay = 3 * time.Millisecond
- maxkey = 100000
- )
-
- var (
- set, getHit, getAll int32
- getMaxLatency, getDuration int64
- )
-
- c := NewCache(NewLRU(5000))
- wg := &sync.WaitGroup{}
- until := time.Now().Add(duration)
- for i := 0; i < concurrentSet; i++ {
- wg.Add(1)
- go func(i int) {
- defer wg.Done()
- r := rand.New(rand.NewSource(time.Now().UnixNano()))
- for time.Now().Before(until) {
- c.Get(0, uint64(r.Intn(maxkey)), func() (int, Value) {
- time.Sleep(delay)
- atomic.AddInt32(&set, 1)
- return 1, 1
- }).Release()
- }
- }(i)
- }
- for i := 0; i < concurrentGet; i++ {
- wg.Add(1)
- go func(i int) {
- defer wg.Done()
- r := rand.New(rand.NewSource(time.Now().UnixNano()))
- for {
- mark := time.Now()
- if mark.Before(until) {
- h := c.Get(0, uint64(r.Intn(maxkey)), nil)
- latency := int64(time.Now().Sub(mark))
- m := atomic.LoadInt64(&getMaxLatency)
- if latency > m {
- atomic.CompareAndSwapInt64(&getMaxLatency, m, latency)
- }
- atomic.AddInt64(&getDuration, latency)
- if h != nil {
- atomic.AddInt32(&getHit, 1)
- h.Release()
- }
- atomic.AddInt32(&getAll, 1)
- } else {
- break
- }
- }
- }(i)
- }
-
- wg.Wait()
- getAvglatency := time.Duration(getDuration) / time.Duration(getAll)
- t.Logf("set=%d getHit=%d getAll=%d getMaxLatency=%v getAvgLatency=%v",
- set, getHit, getAll, time.Duration(getMaxLatency), getAvglatency)
-
- if getAvglatency > delay/3 {
- t.Errorf("get avg latency > %v: got=%v", delay/3, getAvglatency)
- }
-}
-
-func TestLRUCache_HitMiss(t *testing.T) {
- cases := []struct {
- key uint64
- value string
- }{
- {1, "vvvvvvvvv"},
- {100, "v1"},
- {0, "v2"},
- {12346, "v3"},
- {777, "v4"},
- {999, "v5"},
- {7654, "v6"},
- {2, "v7"},
- {3, "v8"},
- {9, "v9"},
- }
-
- setfin := 0
- c := NewCache(NewLRU(1000))
- for i, x := range cases {
- set(c, 0, x.key, x.value, len(x.value), func() {
- setfin++
- }).Release()
- for j, y := range cases {
- h := c.Get(0, y.key, nil)
- if j <= i {
- // should hit
- if h == nil {
- t.Errorf("case '%d' iteration '%d' is miss", i, j)
- } else {
- if x := h.Value().(releaserFunc).value.(string); x != y.value {
- t.Errorf("case '%d' iteration '%d' has invalid value got '%s', want '%s'", i, j, x, y.value)
- }
- }
- } else {
- // should miss
- if h != nil {
- t.Errorf("case '%d' iteration '%d' is hit , value '%s'", i, j, h.Value().(releaserFunc).value.(string))
- }
- }
- if h != nil {
- h.Release()
- }
- }
- }
-
- for i, x := range cases {
- finalizerOk := false
- c.Delete(0, x.key, func() {
- finalizerOk = true
- })
-
- if !finalizerOk {
- t.Errorf("case %d delete finalizer not executed", i)
- }
-
- for j, y := range cases {
- h := c.Get(0, y.key, nil)
- if j > i {
- // should hit
- if h == nil {
- t.Errorf("case '%d' iteration '%d' is miss", i, j)
- } else {
- if x := h.Value().(releaserFunc).value.(string); x != y.value {
- t.Errorf("case '%d' iteration '%d' has invalid value got '%s', want '%s'", i, j, x, y.value)
- }
- }
- } else {
- // should miss
- if h != nil {
- t.Errorf("case '%d' iteration '%d' is hit, value '%s'", i, j, h.Value().(releaserFunc).value.(string))
- }
- }
- if h != nil {
- h.Release()
- }
- }
- }
-
- if setfin != len(cases) {
- t.Errorf("some set finalizer may not be executed, want=%d got=%d", len(cases), setfin)
- }
-}
-
-func TestLRUCache_Eviction(t *testing.T) {
- c := NewCache(NewLRU(12))
- o1 := set(c, 0, 1, 1, 1, nil)
- set(c, 0, 2, 2, 1, nil).Release()
- set(c, 0, 3, 3, 1, nil).Release()
- set(c, 0, 4, 4, 1, nil).Release()
- set(c, 0, 5, 5, 1, nil).Release()
- if h := c.Get(0, 2, nil); h != nil { // 1,3,4,5,2
- h.Release()
- }
- set(c, 0, 9, 9, 10, nil).Release() // 5,2,9
-
- for _, key := range []uint64{9, 2, 5, 1} {
- h := c.Get(0, key, nil)
- if h == nil {
- t.Errorf("miss for key '%d'", key)
- } else {
- if x := h.Value().(int); x != int(key) {
- t.Errorf("invalid value for key '%d' want '%d', got '%d'", key, key, x)
- }
- h.Release()
- }
- }
- o1.Release()
- for _, key := range []uint64{1, 2, 5} {
- h := c.Get(0, key, nil)
- if h == nil {
- t.Errorf("miss for key '%d'", key)
- } else {
- if x := h.Value().(int); x != int(key) {
- t.Errorf("invalid value for key '%d' want '%d', got '%d'", key, key, x)
- }
- h.Release()
- }
- }
- for _, key := range []uint64{3, 4, 9} {
- h := c.Get(0, key, nil)
- if h != nil {
- t.Errorf("hit for key '%d'", key)
- if x := h.Value().(int); x != int(key) {
- t.Errorf("invalid value for key '%d' want '%d', got '%d'", key, key, x)
- }
- h.Release()
- }
- }
-}
-
-func TestLRUCache_Evict(t *testing.T) {
- c := NewCache(NewLRU(6))
- set(c, 0, 1, 1, 1, nil).Release()
- set(c, 0, 2, 2, 1, nil).Release()
- set(c, 1, 1, 4, 1, nil).Release()
- set(c, 1, 2, 5, 1, nil).Release()
- set(c, 2, 1, 6, 1, nil).Release()
- set(c, 2, 2, 7, 1, nil).Release()
-
- for ns := 0; ns < 3; ns++ {
- for key := 1; key < 3; key++ {
- if h := c.Get(uint64(ns), uint64(key), nil); h != nil {
- h.Release()
- } else {
- t.Errorf("Cache.Get on #%d.%d return nil", ns, key)
- }
- }
- }
-
- if ok := c.Evict(0, 1); !ok {
- t.Error("first Cache.Evict on #0.1 return false")
- }
- if ok := c.Evict(0, 1); ok {
- t.Error("second Cache.Evict on #0.1 return true")
- }
- if h := c.Get(0, 1, nil); h != nil {
- t.Errorf("Cache.Get on #0.1 return non-nil: %v", h.Value())
- }
-
- c.EvictNS(1)
- if h := c.Get(1, 1, nil); h != nil {
- t.Errorf("Cache.Get on #1.1 return non-nil: %v", h.Value())
- }
- if h := c.Get(1, 2, nil); h != nil {
- t.Errorf("Cache.Get on #1.2 return non-nil: %v", h.Value())
- }
-
- c.EvictAll()
- for ns := 0; ns < 3; ns++ {
- for key := 1; key < 3; key++ {
- if h := c.Get(uint64(ns), uint64(key), nil); h != nil {
- t.Errorf("Cache.Get on #%d.%d return non-nil: %v", ns, key, h.Value())
- }
- }
- }
-}
-
-func TestLRUCache_Delete(t *testing.T) {
- delFuncCalled := 0
- delFunc := func() {
- delFuncCalled++
- }
-
- c := NewCache(NewLRU(2))
- set(c, 0, 1, 1, 1, nil).Release()
- set(c, 0, 2, 2, 1, nil).Release()
-
- if ok := c.Delete(0, 1, delFunc); !ok {
- t.Error("Cache.Delete on #1 return false")
- }
- if h := c.Get(0, 1, nil); h != nil {
- t.Errorf("Cache.Get on #1 return non-nil: %v", h.Value())
- }
- if ok := c.Delete(0, 1, delFunc); ok {
- t.Error("Cache.Delete on #1 return true")
- }
-
- h2 := c.Get(0, 2, nil)
- if h2 == nil {
- t.Error("Cache.Get on #2 return nil")
- }
- if ok := c.Delete(0, 2, delFunc); !ok {
- t.Error("(1) Cache.Delete on #2 return false")
- }
- if ok := c.Delete(0, 2, delFunc); !ok {
- t.Error("(2) Cache.Delete on #2 return false")
- }
-
- set(c, 0, 3, 3, 1, nil).Release()
- set(c, 0, 4, 4, 1, nil).Release()
- c.Get(0, 2, nil).Release()
-
- for key := 2; key <= 4; key++ {
- if h := c.Get(0, uint64(key), nil); h != nil {
- h.Release()
- } else {
- t.Errorf("Cache.Get on #%d return nil", key)
- }
- }
-
- h2.Release()
- if h := c.Get(0, 2, nil); h != nil {
- t.Errorf("Cache.Get on #2 return non-nil: %v", h.Value())
- }
-
- if delFuncCalled != 4 {
- t.Errorf("delFunc isn't called 4 times: got=%d", delFuncCalled)
- }
-}
-
-func TestLRUCache_Close(t *testing.T) {
- relFuncCalled := 0
- relFunc := func() {
- relFuncCalled++
- }
- delFuncCalled := 0
- delFunc := func() {
- delFuncCalled++
- }
-
- c := NewCache(NewLRU(2))
- set(c, 0, 1, 1, 1, relFunc).Release()
- set(c, 0, 2, 2, 1, relFunc).Release()
-
- h3 := set(c, 0, 3, 3, 1, relFunc)
- if h3 == nil {
- t.Error("Cache.Get on #3 return nil")
- }
- if ok := c.Delete(0, 3, delFunc); !ok {
- t.Error("Cache.Delete on #3 return false")
- }
-
- c.Close()
-
- if relFuncCalled != 3 {
- t.Errorf("relFunc isn't called 3 times: got=%d", relFuncCalled)
- }
- if delFuncCalled != 1 {
- t.Errorf("delFunc isn't called 1 times: got=%d", delFuncCalled)
- }
-}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/corrupt_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/corrupt_test.go
deleted file mode 100644
index a351874ed..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/corrupt_test.go
+++ /dev/null
@@ -1,500 +0,0 @@
-// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com>
-// All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package leveldb
-
-import (
- "bytes"
- "fmt"
- "github.com/syndtr/goleveldb/leveldb/filter"
- "github.com/syndtr/goleveldb/leveldb/opt"
- "github.com/syndtr/goleveldb/leveldb/storage"
- "io"
- "math/rand"
- "testing"
-)
-
-const ctValSize = 1000
-
-type dbCorruptHarness struct {
- dbHarness
-}
-
-func newDbCorruptHarnessWopt(t *testing.T, o *opt.Options) *dbCorruptHarness {
- h := new(dbCorruptHarness)
- h.init(t, o)
- return h
-}
-
-func newDbCorruptHarness(t *testing.T) *dbCorruptHarness {
- return newDbCorruptHarnessWopt(t, &opt.Options{
- BlockCacheCapacity: 100,
- Strict: opt.StrictJournalChecksum,
- })
-}
-
-func (h *dbCorruptHarness) recover() {
- p := &h.dbHarness
- t := p.t
-
- var err error
- p.db, err = Recover(h.stor, h.o)
- if err != nil {
- t.Fatal("Repair: got error: ", err)
- }
-}
-
-func (h *dbCorruptHarness) build(n int) {
- p := &h.dbHarness
- t := p.t
- db := p.db
-
- batch := new(Batch)
- for i := 0; i < n; i++ {
- batch.Reset()
- batch.Put(tkey(i), tval(i, ctValSize))
- err := db.Write(batch, p.wo)
- if err != nil {
- t.Fatal("write error: ", err)
- }
- }
-}
-
-func (h *dbCorruptHarness) buildShuffled(n int, rnd *rand.Rand) {
- p := &h.dbHarness
- t := p.t
- db := p.db
-
- batch := new(Batch)
- for i := range rnd.Perm(n) {
- batch.Reset()
- batch.Put(tkey(i), tval(i, ctValSize))
- err := db.Write(batch, p.wo)
- if err != nil {
- t.Fatal("write error: ", err)
- }
- }
-}
-
-func (h *dbCorruptHarness) deleteRand(n, max int, rnd *rand.Rand) {
- p := &h.dbHarness
- t := p.t
- db := p.db
-
- batch := new(Batch)
- for i := 0; i < n; i++ {
- batch.Reset()
- batch.Delete(tkey(rnd.Intn(max)))
- err := db.Write(batch, p.wo)
- if err != nil {
- t.Fatal("write error: ", err)
- }
- }
-}
-
-func (h *dbCorruptHarness) corrupt(ft storage.FileType, fi, offset, n int) {
- p := &h.dbHarness
- t := p.t
-
- ff, _ := p.stor.GetFiles(ft)
- sff := files(ff)
- sff.sort()
- if fi < 0 {
- fi = len(sff) - 1
- }
- if fi >= len(sff) {
- t.Fatalf("no such file with type %q with index %d", ft, fi)
- }
-
- file := sff[fi]
-
- r, err := file.Open()
- if err != nil {
- t.Fatal("cannot open file: ", err)
- }
- x, err := r.Seek(0, 2)
- if err != nil {
- t.Fatal("cannot query file size: ", err)
- }
- m := int(x)
- if _, err := r.Seek(0, 0); err != nil {
- t.Fatal(err)
- }
-
- if offset < 0 {
- if -offset > m {
- offset = 0
- } else {
- offset = m + offset
- }
- }
- if offset > m {
- offset = m
- }
- if offset+n > m {
- n = m - offset
- }
-
- buf := make([]byte, m)
- _, err = io.ReadFull(r, buf)
- if err != nil {
- t.Fatal("cannot read file: ", err)
- }
- r.Close()
-
- for i := 0; i < n; i++ {
- buf[offset+i] ^= 0x80
- }
-
- err = file.Remove()
- if err != nil {
- t.Fatal("cannot remove old file: ", err)
- }
- w, err := file.Create()
- if err != nil {
- t.Fatal("cannot create new file: ", err)
- }
- _, err = w.Write(buf)
- if err != nil {
- t.Fatal("cannot write new file: ", err)
- }
- w.Close()
-}
-
-func (h *dbCorruptHarness) removeAll(ft storage.FileType) {
- ff, err := h.stor.GetFiles(ft)
- if err != nil {
- h.t.Fatal("get files: ", err)
- }
- for _, f := range ff {
- if err := f.Remove(); err != nil {
- h.t.Error("remove file: ", err)
- }
- }
-}
-
-func (h *dbCorruptHarness) removeOne(ft storage.FileType) {
- ff, err := h.stor.GetFiles(ft)
- if err != nil {
- h.t.Fatal("get files: ", err)
- }
- f := ff[rand.Intn(len(ff))]
- h.t.Logf("removing file @%d", f.Num())
- if err := f.Remove(); err != nil {
- h.t.Error("remove file: ", err)
- }
-}
-
-func (h *dbCorruptHarness) check(min, max int) {
- p := &h.dbHarness
- t := p.t
- db := p.db
-
- var n, badk, badv, missed, good int
- iter := db.NewIterator(nil, p.ro)
- for iter.Next() {
- k := 0
- fmt.Sscanf(string(iter.Key()), "%d", &k)
- if k < n {
- badk++
- continue
- }
- missed += k - n
- n = k + 1
- if !bytes.Equal(iter.Value(), tval(k, ctValSize)) {
- badv++
- } else {
- good++
- }
- }
- err := iter.Error()
- iter.Release()
- t.Logf("want=%d..%d got=%d badkeys=%d badvalues=%d missed=%d, err=%v",
- min, max, good, badk, badv, missed, err)
- if good < min || good > max {
- t.Errorf("good entries number not in range")
- }
-}
-
-func TestCorruptDB_Journal(t *testing.T) {
- h := newDbCorruptHarness(t)
-
- h.build(100)
- h.check(100, 100)
- h.closeDB()
- h.corrupt(storage.TypeJournal, -1, 19, 1)
- h.corrupt(storage.TypeJournal, -1, 32*1024+1000, 1)
-
- h.openDB()
- h.check(36, 36)
-
- h.close()
-}
-
-func TestCorruptDB_Table(t *testing.T) {
- h := newDbCorruptHarness(t)
-
- h.build(100)
- h.compactMem()
- h.compactRangeAt(0, "", "")
- h.compactRangeAt(1, "", "")
- h.closeDB()
- h.corrupt(storage.TypeTable, -1, 100, 1)
-
- h.openDB()
- h.check(99, 99)
-
- h.close()
-}
-
-func TestCorruptDB_TableIndex(t *testing.T) {
- h := newDbCorruptHarness(t)
-
- h.build(10000)
- h.compactMem()
- h.closeDB()
- h.corrupt(storage.TypeTable, -1, -2000, 500)
-
- h.openDB()
- h.check(5000, 9999)
-
- h.close()
-}
-
-func TestCorruptDB_MissingManifest(t *testing.T) {
- rnd := rand.New(rand.NewSource(0x0badda7a))
- h := newDbCorruptHarnessWopt(t, &opt.Options{
- BlockCacheCapacity: 100,
- Strict: opt.StrictJournalChecksum,
- WriteBuffer: 1000 * 60,
- })
-
- h.build(1000)
- h.compactMem()
- h.buildShuffled(1000, rnd)
- h.compactMem()
- h.deleteRand(500, 1000, rnd)
- h.compactMem()
- h.buildShuffled(1000, rnd)
- h.compactMem()
- h.deleteRand(500, 1000, rnd)
- h.compactMem()
- h.buildShuffled(1000, rnd)
- h.compactMem()
- h.closeDB()
-
- h.stor.SetIgnoreOpenErr(storage.TypeManifest)
- h.removeAll(storage.TypeManifest)
- h.openAssert(false)
- h.stor.SetIgnoreOpenErr(0)
-
- h.recover()
- h.check(1000, 1000)
- h.build(1000)
- h.compactMem()
- h.compactRange("", "")
- h.closeDB()
-
- h.recover()
- h.check(1000, 1000)
-
- h.close()
-}
-
-func TestCorruptDB_SequenceNumberRecovery(t *testing.T) {
- h := newDbCorruptHarness(t)
-
- h.put("foo", "v1")
- h.put("foo", "v2")
- h.put("foo", "v3")
- h.put("foo", "v4")
- h.put("foo", "v5")
- h.closeDB()
-
- h.recover()
- h.getVal("foo", "v5")
- h.put("foo", "v6")
- h.getVal("foo", "v6")
-
- h.reopenDB()
- h.getVal("foo", "v6")
-
- h.close()
-}
-
-func TestCorruptDB_SequenceNumberRecoveryTable(t *testing.T) {
- h := newDbCorruptHarness(t)
-
- h.put("foo", "v1")
- h.put("foo", "v2")
- h.put("foo", "v3")
- h.compactMem()
- h.put("foo", "v4")
- h.put("foo", "v5")
- h.compactMem()
- h.closeDB()
-
- h.recover()
- h.getVal("foo", "v5")
- h.put("foo", "v6")
- h.getVal("foo", "v6")
-
- h.reopenDB()
- h.getVal("foo", "v6")
-
- h.close()
-}
-
-func TestCorruptDB_CorruptedManifest(t *testing.T) {
- h := newDbCorruptHarness(t)
-
- h.put("foo", "hello")
- h.compactMem()
- h.compactRange("", "")
- h.closeDB()
- h.corrupt(storage.TypeManifest, -1, 0, 1000)
- h.openAssert(false)
-
- h.recover()
- h.getVal("foo", "hello")
-
- h.close()
-}
-
-func TestCorruptDB_CompactionInputError(t *testing.T) {
- h := newDbCorruptHarness(t)
-
- h.build(10)
- h.compactMem()
- h.closeDB()
- h.corrupt(storage.TypeTable, -1, 100, 1)
-
- h.openDB()
- h.check(9, 9)
-
- h.build(10000)
- h.check(10000, 10000)
-
- h.close()
-}
-
-func TestCorruptDB_UnrelatedKeys(t *testing.T) {
- h := newDbCorruptHarness(t)
-
- h.build(10)
- h.compactMem()
- h.closeDB()
- h.corrupt(storage.TypeTable, -1, 100, 1)
-
- h.openDB()
- h.put(string(tkey(1000)), string(tval(1000, ctValSize)))
- h.getVal(string(tkey(1000)), string(tval(1000, ctValSize)))
- h.compactMem()
- h.getVal(string(tkey(1000)), string(tval(1000, ctValSize)))
-
- h.close()
-}
-
-func TestCorruptDB_Level0NewerFileHasOlderSeqnum(t *testing.T) {
- h := newDbCorruptHarness(t)
-
- h.put("a", "v1")
- h.put("b", "v1")
- h.compactMem()
- h.put("a", "v2")
- h.put("b", "v2")
- h.compactMem()
- h.put("a", "v3")
- h.put("b", "v3")
- h.compactMem()
- h.put("c", "v0")
- h.put("d", "v0")
- h.compactMem()
- h.compactRangeAt(1, "", "")
- h.closeDB()
-
- h.recover()
- h.getVal("a", "v3")
- h.getVal("b", "v3")
- h.getVal("c", "v0")
- h.getVal("d", "v0")
-
- h.close()
-}
-
-func TestCorruptDB_RecoverInvalidSeq_Issue53(t *testing.T) {
- h := newDbCorruptHarness(t)
-
- h.put("a", "v1")
- h.put("b", "v1")
- h.compactMem()
- h.put("a", "v2")
- h.put("b", "v2")
- h.compactMem()
- h.put("a", "v3")
- h.put("b", "v3")
- h.compactMem()
- h.put("c", "v0")
- h.put("d", "v0")
- h.compactMem()
- h.compactRangeAt(0, "", "")
- h.closeDB()
-
- h.recover()
- h.getVal("a", "v3")
- h.getVal("b", "v3")
- h.getVal("c", "v0")
- h.getVal("d", "v0")
-
- h.close()
-}
-
-func TestCorruptDB_MissingTableFiles(t *testing.T) {
- h := newDbCorruptHarness(t)
-
- h.put("a", "v1")
- h.put("b", "v1")
- h.compactMem()
- h.put("c", "v2")
- h.put("d", "v2")
- h.compactMem()
- h.put("e", "v3")
- h.put("f", "v3")
- h.closeDB()
-
- h.removeOne(storage.TypeTable)
- h.openAssert(false)
-
- h.close()
-}
-
-func TestCorruptDB_RecoverTable(t *testing.T) {
- h := newDbCorruptHarnessWopt(t, &opt.Options{
- WriteBuffer: 112 * opt.KiB,
- CompactionTableSize: 90 * opt.KiB,
- Filter: filter.NewBloomFilter(10),
- })
-
- h.build(1000)
- h.compactMem()
- h.compactRangeAt(0, "", "")
- h.compactRangeAt(1, "", "")
- seq := h.db.seq
- h.closeDB()
- h.corrupt(storage.TypeTable, 0, 1000, 1)
- h.corrupt(storage.TypeTable, 3, 10000, 1)
- // Corrupted filter shouldn't affect recovery.
- h.corrupt(storage.TypeTable, 3, 113888, 10)
- h.corrupt(storage.TypeTable, -1, 20000, 1)
-
- h.recover()
- if h.db.seq != seq {
- t.Errorf("invalid seq, want=%d got=%d", seq, h.db.seq)
- }
- h.check(985, 985)
-
- h.close()
-}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db.go
index 323353b2a..537addb62 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db.go
@@ -36,14 +36,14 @@ type DB struct {
s *session
// MemDB.
- memMu sync.RWMutex
- memPool chan *memdb.DB
- mem, frozenMem *memDB
- journal *journal.Writer
- journalWriter storage.Writer
- journalFile storage.File
- frozenJournalFile storage.File
- frozenSeq uint64
+ memMu sync.RWMutex
+ memPool chan *memdb.DB
+ mem, frozenMem *memDB
+ journal *journal.Writer
+ journalWriter storage.Writer
+ journalFd storage.FileDesc
+ frozenJournalFd storage.FileDesc
+ frozenSeq uint64
// Snapshot.
snapsMu sync.Mutex
@@ -61,15 +61,19 @@ type DB struct {
writeDelayN int
journalC chan *Batch
journalAckC chan error
+ tr *Transaction
// Compaction.
- tcompCmdC chan cCmd
- tcompPauseC chan chan<- struct{}
- mcompCmdC chan cCmd
- compErrC chan error
- compPerErrC chan error
- compErrSetC chan error
- compStats []cStats
+ compCommitLk sync.Mutex
+ tcompCmdC chan cCmd
+ tcompPauseC chan chan<- struct{}
+ mcompCmdC chan cCmd
+ compErrC chan error
+ compPerErrC chan error
+ compErrSetC chan error
+ compWriteLocking bool
+ compStats cStats
+ memdbMaxLevel int // For testing.
// Close.
closeW sync.WaitGroup
@@ -103,33 +107,48 @@ func openDB(s *session) (*DB, error) {
compErrC: make(chan error),
compPerErrC: make(chan error),
compErrSetC: make(chan error),
- compStats: make([]cStats, s.o.GetNumLevel()),
// Close
closeC: make(chan struct{}),
}
- if err := db.recoverJournal(); err != nil {
- return nil, err
- }
+ // Read-only mode.
+ readOnly := s.o.GetReadOnly()
- // Remove any obsolete files.
- if err := db.checkAndCleanFiles(); err != nil {
- // Close journal.
- if db.journal != nil {
- db.journal.Close()
- db.journalWriter.Close()
+ if readOnly {
+ // Recover journals (read-only mode).
+ if err := db.recoverJournalRO(); err != nil {
+ return nil, err
}
- return nil, err
+ } else {
+ // Recover journals.
+ if err := db.recoverJournal(); err != nil {
+ return nil, err
+ }
+
+ // Remove any obsolete files.
+ if err := db.checkAndCleanFiles(); err != nil {
+ // Close journal.
+ if db.journal != nil {
+ db.journal.Close()
+ db.journalWriter.Close()
+ }
+ return nil, err
+ }
+
}
// Doesn't need to be included in the wait group.
go db.compactionError()
go db.mpoolDrain()
- db.closeW.Add(3)
- go db.tCompaction()
- go db.mCompaction()
- go db.jWriter()
+ if readOnly {
+ db.SetReadOnly()
+ } else {
+ db.closeW.Add(3)
+ go db.tCompaction()
+ go db.mCompaction()
+ go db.jWriter()
+ }
s.logf("db@open done T·%v", time.Since(start))
@@ -192,7 +211,7 @@ func Open(stor storage.Storage, o *opt.Options) (db *DB, err error) {
// The returned DB instance is goroutine-safe.
// The DB must be closed after use, by calling Close method.
func OpenFile(path string, o *opt.Options) (db *DB, err error) {
- stor, err := storage.OpenFile(path)
+ stor, err := storage.OpenFile(path, o.GetReadOnly())
if err != nil {
return
}
@@ -242,7 +261,7 @@ func Recover(stor storage.Storage, o *opt.Options) (db *DB, err error) {
// The returned DB instance is goroutine-safe.
// The DB must be closed after use, by calling Close method.
func RecoverFile(path string, o *opt.Options) (db *DB, err error) {
- stor, err := storage.OpenFile(path)
+ stor, err := storage.OpenFile(path, false)
if err != nil {
return
}
@@ -261,12 +280,11 @@ func recoverTable(s *session, o *opt.Options) error {
o.Strict &= ^opt.StrictReader
// Get all tables and sort it by file number.
- tableFiles_, err := s.getFiles(storage.TypeTable)
+ fds, err := s.stor.List(storage.TypeTable)
if err != nil {
return err
}
- tableFiles := files(tableFiles_)
- tableFiles.sort()
+ sortFds(fds)
var (
maxSeq uint64
@@ -274,21 +292,22 @@ func recoverTable(s *session, o *opt.Options) error {
// We will drop corrupted table.
strict = o.GetStrict(opt.StrictRecovery)
+ noSync = o.GetNoSync()
- rec = &sessionRecord{numLevel: o.GetNumLevel()}
+ rec = &sessionRecord{}
bpool = util.NewBufferPool(o.GetBlockSize() + 5)
)
- buildTable := func(iter iterator.Iterator) (tmp storage.File, size int64, err error) {
- tmp = s.newTemp()
- writer, err := tmp.Create()
+ buildTable := func(iter iterator.Iterator) (tmpFd storage.FileDesc, size int64, err error) {
+ tmpFd = s.newTemp()
+ writer, err := s.stor.Create(tmpFd)
if err != nil {
return
}
defer func() {
writer.Close()
if err != nil {
- tmp.Remove()
- tmp = nil
+ s.stor.Remove(tmpFd)
+ tmpFd = storage.FileDesc{}
}
}()
@@ -311,16 +330,18 @@ func recoverTable(s *session, o *opt.Options) error {
if err != nil {
return
}
- err = writer.Sync()
- if err != nil {
- return
+ if !noSync {
+ err = writer.Sync()
+ if err != nil {
+ return
+ }
}
size = int64(tw.BytesLen())
return
}
- recoverTable := func(file storage.File) error {
- s.logf("table@recovery recovering @%d", file.Num())
- reader, err := file.Open()
+ recoverTable := func(fd storage.FileDesc) error {
+ s.logf("table@recovery recovering @%d", fd.Num)
+ reader, err := s.stor.Open(fd)
if err != nil {
return err
}
@@ -342,7 +363,7 @@ func recoverTable(s *session, o *opt.Options) error {
tgoodKey, tcorruptedKey, tcorruptedBlock int
imin, imax []byte
)
- tr, err := table.NewReader(reader, size, storage.NewFileInfo(file), nil, bpool, o)
+ tr, err := table.NewReader(reader, size, fd, nil, bpool, o)
if err != nil {
return err
}
@@ -350,7 +371,7 @@ func recoverTable(s *session, o *opt.Options) error {
if itererr, ok := iter.(iterator.ErrorCallbackSetter); ok {
itererr.SetErrorCallback(func(err error) {
if errors.IsCorrupted(err) {
- s.logf("table@recovery block corruption @%d %q", file.Num(), err)
+ s.logf("table@recovery block corruption @%d %q", fd.Num, err)
tcorruptedBlock++
}
})
@@ -385,23 +406,23 @@ func recoverTable(s *session, o *opt.Options) error {
if strict && (tcorruptedKey > 0 || tcorruptedBlock > 0) {
droppedTable++
- s.logf("table@recovery dropped @%d Gk·%d Ck·%d Cb·%d S·%d Q·%d", file.Num(), tgoodKey, tcorruptedKey, tcorruptedBlock, size, tSeq)
+ s.logf("table@recovery dropped @%d Gk·%d Ck·%d Cb·%d S·%d Q·%d", fd.Num, tgoodKey, tcorruptedKey, tcorruptedBlock, size, tSeq)
return nil
}
if tgoodKey > 0 {
if tcorruptedKey > 0 || tcorruptedBlock > 0 {
// Rebuild the table.
- s.logf("table@recovery rebuilding @%d", file.Num())
+ s.logf("table@recovery rebuilding @%d", fd.Num)
iter := tr.NewIterator(nil, nil)
- tmp, newSize, err := buildTable(iter)
+ tmpFd, newSize, err := buildTable(iter)
iter.Release()
if err != nil {
return err
}
closed = true
reader.Close()
- if err := file.Replace(tmp); err != nil {
+ if err := s.stor.Rename(tmpFd, fd); err != nil {
return err
}
size = newSize
@@ -411,30 +432,30 @@ func recoverTable(s *session, o *opt.Options) error {
}
recoveredKey += tgoodKey
// Add table to level 0.
- rec.addTable(0, file.Num(), uint64(size), imin, imax)
- s.logf("table@recovery recovered @%d Gk·%d Ck·%d Cb·%d S·%d Q·%d", file.Num(), tgoodKey, tcorruptedKey, tcorruptedBlock, size, tSeq)
+ rec.addTable(0, fd.Num, size, imin, imax)
+ s.logf("table@recovery recovered @%d Gk·%d Ck·%d Cb·%d S·%d Q·%d", fd.Num, tgoodKey, tcorruptedKey, tcorruptedBlock, size, tSeq)
} else {
droppedTable++
- s.logf("table@recovery unrecoverable @%d Ck·%d Cb·%d S·%d", file.Num(), tcorruptedKey, tcorruptedBlock, size)
+ s.logf("table@recovery unrecoverable @%d Ck·%d Cb·%d S·%d", fd.Num, tcorruptedKey, tcorruptedBlock, size)
}
return nil
}
// Recover all tables.
- if len(tableFiles) > 0 {
- s.logf("table@recovery F·%d", len(tableFiles))
+ if len(fds) > 0 {
+ s.logf("table@recovery F·%d", len(fds))
// Mark file number as used.
- s.markFileNum(tableFiles[len(tableFiles)-1].Num())
+ s.markFileNum(fds[len(fds)-1].Num)
- for _, file := range tableFiles {
- if err := recoverTable(file); err != nil {
+ for _, fd := range fds {
+ if err := recoverTable(fd); err != nil {
return err
}
}
- s.logf("table@recovery recovered F·%d N·%d Gk·%d Ck·%d Q·%d", len(tableFiles), recoveredKey, goodKey, corruptedKey, maxSeq)
+ s.logf("table@recovery recovered F·%d N·%d Gk·%d Ck·%d Q·%d", len(fds), recoveredKey, goodKey, corruptedKey, maxSeq)
}
// Set sequence number.
@@ -450,132 +471,136 @@ func recoverTable(s *session, o *opt.Options) error {
}
func (db *DB) recoverJournal() error {
- // Get all tables and sort it by file number.
- journalFiles_, err := db.s.getFiles(storage.TypeJournal)
+ // Get all journals and sort it by file number.
+ fds_, err := db.s.stor.List(storage.TypeJournal)
if err != nil {
return err
}
- journalFiles := files(journalFiles_)
- journalFiles.sort()
+ sortFds(fds_)
- // Discard older journal.
- prev := -1
- for i, file := range journalFiles {
- if file.Num() >= db.s.stJournalNum {
- if prev >= 0 {
- i--
- journalFiles[i] = journalFiles[prev]
- }
- journalFiles = journalFiles[i:]
- break
- } else if file.Num() == db.s.stPrevJournalNum {
- prev = i
- }
- }
-
- var jr *journal.Reader
- var of storage.File
- var mem *memdb.DB
- batch := new(Batch)
- cm := newCMem(db.s)
- buf := new(util.Buffer)
- // Options.
- strict := db.s.o.GetStrict(opt.StrictJournal)
- checksum := db.s.o.GetStrict(opt.StrictJournalChecksum)
- writeBuffer := db.s.o.GetWriteBuffer()
- recoverJournal := func(file storage.File) error {
- db.logf("journal@recovery recovering @%d", file.Num())
- reader, err := file.Open()
- if err != nil {
- return err
+ // Journals that will be recovered.
+ var fds []storage.FileDesc
+ for _, fd := range fds_ {
+ if fd.Num >= db.s.stJournalNum || fd.Num == db.s.stPrevJournalNum {
+ fds = append(fds, fd)
}
- defer reader.Close()
+ }
- // Create/reset journal reader instance.
- if jr == nil {
- jr = journal.NewReader(reader, dropper{db.s, file}, strict, checksum)
- } else {
- jr.Reset(reader, dropper{db.s, file}, strict, checksum)
- }
+ var (
+ ofd storage.FileDesc // Obsolete file.
+ rec = &sessionRecord{}
+ )
- // Flush memdb and remove obsolete journal file.
- if of != nil {
- if mem.Len() > 0 {
- if err := cm.flush(mem, 0); err != nil {
- return err
- }
- }
- if err := cm.commit(file.Num(), db.seq); err != nil {
+ // Recover journals.
+ if len(fds) > 0 {
+ db.logf("journal@recovery F·%d", len(fds))
+
+ // Mark file number as used.
+ db.s.markFileNum(fds[len(fds)-1].Num)
+
+ var (
+ // Options.
+ strict = db.s.o.GetStrict(opt.StrictJournal)
+ checksum = db.s.o.GetStrict(opt.StrictJournalChecksum)
+ writeBuffer = db.s.o.GetWriteBuffer()
+
+ jr *journal.Reader
+ mdb = memdb.New(db.s.icmp, writeBuffer)
+ buf = &util.Buffer{}
+ batch = &Batch{}
+ )
+
+ for _, fd := range fds {
+ db.logf("journal@recovery recovering @%d", fd.Num)
+
+ fr, err := db.s.stor.Open(fd)
+ if err != nil {
return err
}
- cm.reset()
- of.Remove()
- of = nil
- }
- // Replay journal to memdb.
- mem.Reset()
- for {
- r, err := jr.Next()
- if err != nil {
- if err == io.EOF {
- break
- }
- return errors.SetFile(err, file)
+ // Create or reset journal reader instance.
+ if jr == nil {
+ jr = journal.NewReader(fr, dropper{db.s, fd}, strict, checksum)
+ } else {
+ jr.Reset(fr, dropper{db.s, fd}, strict, checksum)
}
- buf.Reset()
- if _, err := buf.ReadFrom(r); err != nil {
- if err == io.ErrUnexpectedEOF {
- // This is error returned due to corruption, with strict == false.
- continue
- } else {
- return errors.SetFile(err, file)
+ // Flush memdb and remove obsolete journal file.
+ if !ofd.Nil() {
+ if mdb.Len() > 0 {
+ if _, err := db.s.flushMemdb(rec, mdb, 0); err != nil {
+ fr.Close()
+ return err
+ }
}
- }
- if err := batch.memDecodeAndReplay(db.seq, buf.Bytes(), mem); err != nil {
- if strict || !errors.IsCorrupted(err) {
- return errors.SetFile(err, file)
- } else {
- db.s.logf("journal error: %v (skipped)", err)
- // We won't apply sequence number as it might be corrupted.
- continue
+
+ rec.setJournalNum(fd.Num)
+ rec.setSeqNum(db.seq)
+ if err := db.s.commit(rec); err != nil {
+ fr.Close()
+ return err
}
+ rec.resetAddedTables()
+
+ db.s.stor.Remove(ofd)
+ ofd = storage.FileDesc{}
}
- // Save sequence number.
- db.seq = batch.seq + uint64(batch.Len())
+ // Replay journal to memdb.
+ mdb.Reset()
+ for {
+ r, err := jr.Next()
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
- // Flush it if large enough.
- if mem.Size() >= writeBuffer {
- if err := cm.flush(mem, 0); err != nil {
- return err
+ fr.Close()
+ return errors.SetFd(err, fd)
}
- mem.Reset()
- }
- }
- of = file
- return nil
- }
+ buf.Reset()
+ if _, err := buf.ReadFrom(r); err != nil {
+ if err == io.ErrUnexpectedEOF {
+ // This is error returned due to corruption, with strict == false.
+ continue
+ }
+
+ fr.Close()
+ return errors.SetFd(err, fd)
+ }
+ if err := batch.memDecodeAndReplay(db.seq, buf.Bytes(), mdb); err != nil {
+ if !strict && errors.IsCorrupted(err) {
+ db.s.logf("journal error: %v (skipped)", err)
+ // We won't apply sequence number as it might be corrupted.
+ continue
+ }
+
+ fr.Close()
+ return errors.SetFd(err, fd)
+ }
- // Recover all journals.
- if len(journalFiles) > 0 {
- db.logf("journal@recovery F·%d", len(journalFiles))
+ // Save sequence number.
+ db.seq = batch.seq + uint64(batch.Len())
- // Mark file number as used.
- db.s.markFileNum(journalFiles[len(journalFiles)-1].Num())
+ // Flush it if large enough.
+ if mdb.Size() >= writeBuffer {
+ if _, err := db.s.flushMemdb(rec, mdb, 0); err != nil {
+ fr.Close()
+ return err
+ }
- mem = memdb.New(db.s.icmp, writeBuffer)
- for _, file := range journalFiles {
- if err := recoverJournal(file); err != nil {
- return err
+ mdb.Reset()
+ }
}
+
+ fr.Close()
+ ofd = fd
}
- // Flush the last journal.
- if mem.Len() > 0 {
- if err := cm.flush(mem, 0); err != nil {
+ // Flush the last memdb.
+ if mdb.Len() > 0 {
+ if _, err := db.s.flushMemdb(rec, mdb, 0); err != nil {
return err
}
}
@@ -587,8 +612,10 @@ func (db *DB) recoverJournal() error {
}
// Commit.
- if err := cm.commit(db.journalFile.Num(), db.seq); err != nil {
- // Close journal.
+ rec.setJournalNum(db.journalFd.Num)
+ rec.setSeqNum(db.seq)
+ if err := db.s.commit(rec); err != nil {
+ // Close journal on error.
if db.journal != nil {
db.journal.Close()
db.journalWriter.Close()
@@ -597,15 +624,139 @@ func (db *DB) recoverJournal() error {
}
// Remove the last obsolete journal file.
- if of != nil {
- of.Remove()
+ if !ofd.Nil() {
+ db.s.stor.Remove(ofd)
+ }
+
+ return nil
+}
+
+func (db *DB) recoverJournalRO() error {
+ // Get all journals and sort it by file number.
+ fds_, err := db.s.stor.List(storage.TypeJournal)
+ if err != nil {
+ return err
+ }
+ sortFds(fds_)
+
+ // Journals that will be recovered.
+ var fds []storage.FileDesc
+ for _, fd := range fds_ {
+ if fd.Num >= db.s.stJournalNum || fd.Num == db.s.stPrevJournalNum {
+ fds = append(fds, fd)
+ }
+ }
+
+ var (
+ // Options.
+ strict = db.s.o.GetStrict(opt.StrictJournal)
+ checksum = db.s.o.GetStrict(opt.StrictJournalChecksum)
+ writeBuffer = db.s.o.GetWriteBuffer()
+
+ mdb = memdb.New(db.s.icmp, writeBuffer)
+ )
+
+ // Recover journals.
+ if len(fds) > 0 {
+ db.logf("journal@recovery RO·Mode F·%d", len(fds))
+
+ var (
+ jr *journal.Reader
+ buf = &util.Buffer{}
+ batch = &Batch{}
+ )
+
+ for _, fd := range fds {
+ db.logf("journal@recovery recovering @%d", fd.Num)
+
+ fr, err := db.s.stor.Open(fd)
+ if err != nil {
+ return err
+ }
+
+ // Create or reset journal reader instance.
+ if jr == nil {
+ jr = journal.NewReader(fr, dropper{db.s, fd}, strict, checksum)
+ } else {
+ jr.Reset(fr, dropper{db.s, fd}, strict, checksum)
+ }
+
+ // Replay journal to memdb.
+ for {
+ r, err := jr.Next()
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+
+ fr.Close()
+ return errors.SetFd(err, fd)
+ }
+
+ buf.Reset()
+ if _, err := buf.ReadFrom(r); err != nil {
+ if err == io.ErrUnexpectedEOF {
+ // This is error returned due to corruption, with strict == false.
+ continue
+ }
+
+ fr.Close()
+ return errors.SetFd(err, fd)
+ }
+ if err := batch.memDecodeAndReplay(db.seq, buf.Bytes(), mdb); err != nil {
+ if !strict && errors.IsCorrupted(err) {
+ db.s.logf("journal error: %v (skipped)", err)
+ // We won't apply sequence number as it might be corrupted.
+ continue
+ }
+
+ fr.Close()
+ return errors.SetFd(err, fd)
+ }
+
+ // Save sequence number.
+ db.seq = batch.seq + uint64(batch.Len())
+ }
+
+ fr.Close()
+ }
}
+ // Set memDB.
+ db.mem = &memDB{db: db, DB: mdb, ref: 1}
+
return nil
}
-func (db *DB) get(key []byte, seq uint64, ro *opt.ReadOptions) (value []byte, err error) {
- ikey := newIkey(key, seq, ktSeek)
+func memGet(mdb *memdb.DB, ikey iKey, icmp *iComparer) (ok bool, mv []byte, err error) {
+ mk, mv, err := mdb.Find(ikey)
+ if err == nil {
+ ukey, _, kt, kerr := parseIkey(mk)
+ if kerr != nil {
+ // Shouldn't have had happen.
+ panic(kerr)
+ }
+ if icmp.uCompare(ukey, ikey.ukey()) == 0 {
+ if kt == ktDel {
+ return true, nil, ErrNotFound
+ }
+ return true, mv, nil
+
+ }
+ } else if err != ErrNotFound {
+ return true, nil, err
+ }
+ return
+}
+
+func (db *DB) get(auxm *memdb.DB, auxt tFiles, key []byte, seq uint64, ro *opt.ReadOptions) (value []byte, err error) {
+ ikey := makeIkey(nil, key, seq, ktSeek)
+
+ if auxm != nil {
+ if ok, mv, me := memGet(auxm, ikey, db.s.icmp); ok {
+ return append([]byte{}, mv...), me
+ }
+ }
em, fm := db.getMems()
for _, m := range [...]*memDB{em, fm} {
@@ -614,36 +765,36 @@ func (db *DB) get(key []byte, seq uint64, ro *opt.ReadOptions) (value []byte, er
}
defer m.decref()
- mk, mv, me := m.mdb.Find(ikey)
- if me == nil {
- ukey, _, kt, kerr := parseIkey(mk)
- if kerr != nil {
- // Shouldn't have had happen.
- panic(kerr)
- }
- if db.s.icmp.uCompare(ukey, key) == 0 {
- if kt == ktDel {
- return nil, ErrNotFound
- }
- return append([]byte{}, mv...), nil
- }
- } else if me != ErrNotFound {
- return nil, me
+ if ok, mv, me := memGet(m.DB, ikey, db.s.icmp); ok {
+ return append([]byte{}, mv...), me
}
}
v := db.s.version()
- value, cSched, err := v.get(ikey, ro, false)
+ value, cSched, err := v.get(auxt, ikey, ro, false)
v.release()
if cSched {
// Trigger table compaction.
- db.compSendTrigger(db.tcompCmdC)
+ db.compTrigger(db.tcompCmdC)
}
return
}
-func (db *DB) has(key []byte, seq uint64, ro *opt.ReadOptions) (ret bool, err error) {
- ikey := newIkey(key, seq, ktSeek)
+func nilIfNotFound(err error) error {
+ if err == ErrNotFound {
+ return nil
+ }
+ return err
+}
+
+func (db *DB) has(auxm *memdb.DB, auxt tFiles, key []byte, seq uint64, ro *opt.ReadOptions) (ret bool, err error) {
+ ikey := makeIkey(nil, key, seq, ktSeek)
+
+ if auxm != nil {
+ if ok, _, me := memGet(auxm, ikey, db.s.icmp); ok {
+ return me == nil, nilIfNotFound(me)
+ }
+ }
em, fm := db.getMems()
for _, m := range [...]*memDB{em, fm} {
@@ -652,30 +803,17 @@ func (db *DB) has(key []byte, seq uint64, ro *opt.ReadOptions) (ret bool, err er
}
defer m.decref()
- mk, _, me := m.mdb.Find(ikey)
- if me == nil {
- ukey, _, kt, kerr := parseIkey(mk)
- if kerr != nil {
- // Shouldn't have had happen.
- panic(kerr)
- }
- if db.s.icmp.uCompare(ukey, key) == 0 {
- if kt == ktDel {
- return false, nil
- }
- return true, nil
- }
- } else if me != ErrNotFound {
- return false, me
+ if ok, _, me := memGet(m.DB, ikey, db.s.icmp); ok {
+ return me == nil, nilIfNotFound(me)
}
}
v := db.s.version()
- _, cSched, err := v.get(ikey, ro, true)
+ _, cSched, err := v.get(auxt, ikey, ro, true)
v.release()
if cSched {
// Trigger table compaction.
- db.compSendTrigger(db.tcompCmdC)
+ db.compTrigger(db.tcompCmdC)
}
if err == nil {
ret = true
@@ -699,7 +837,7 @@ func (db *DB) Get(key []byte, ro *opt.ReadOptions) (value []byte, err error) {
se := db.acquireSnapshot()
defer db.releaseSnapshot(se)
- return db.get(key, se.seq, ro)
+ return db.get(nil, nil, key, se.seq, ro)
}
// Has returns true if the DB does contains the given key.
@@ -713,11 +851,11 @@ func (db *DB) Has(key []byte, ro *opt.ReadOptions) (ret bool, err error) {
se := db.acquireSnapshot()
defer db.releaseSnapshot(se)
- return db.has(key, se.seq, ro)
+ return db.has(nil, nil, key, se.seq, ro)
}
// NewIterator returns an iterator for the latest snapshot of the
-// uderlying DB.
+// underlying DB.
// The returned iterator is not goroutine-safe, but it is safe to use
// multiple iterators concurrently, with each in a dedicated goroutine.
// It is also safe to use an iterator concurrently with modifying its
@@ -741,7 +879,7 @@ func (db *DB) NewIterator(slice *util.Range, ro *opt.ReadOptions) iterator.Itera
defer db.releaseSnapshot(se)
// Iterator holds 'version' lock, 'version' is immutable so snapshot
// can be released after iterator created.
- return db.newIterator(se.seq, slice, ro)
+ return db.newIterator(nil, nil, se.seq, slice, ro)
}
// GetSnapshot returns a latest snapshot of the underlying DB. A snapshot
@@ -784,7 +922,7 @@ func (db *DB) GetProperty(name string) (value string, err error) {
const prefix = "leveldb."
if !strings.HasPrefix(name, prefix) {
- return "", errors.New("leveldb: GetProperty: unknown property: " + name)
+ return "", ErrNotFound
}
p := name[len(prefix):]
@@ -797,8 +935,8 @@ func (db *DB) GetProperty(name string) (value string, err error) {
var level uint
var rest string
n, _ := fmt.Sscanf(p[len(numFilesPrefix):], "%d%s", &level, &rest)
- if n != 1 || int(level) >= db.s.o.GetNumLevel() {
- err = errors.New("leveldb: GetProperty: invalid property: " + name)
+ if n != 1 {
+ err = ErrNotFound
} else {
value = fmt.Sprint(v.tLen(int(level)))
}
@@ -806,8 +944,8 @@ func (db *DB) GetProperty(name string) (value string, err error) {
value = "Compactions\n" +
" Level | Tables | Size(MB) | Time(sec) | Read(MB) | Write(MB)\n" +
"-------+------------+---------------+---------------+---------------+---------------\n"
- for level, tables := range v.tables {
- duration, read, write := db.compStats[level].get()
+ for level, tables := range v.levels {
+ duration, read, write := db.compStats.getStat(level)
if len(tables) == 0 && duration == 0 {
continue
}
@@ -816,10 +954,10 @@ func (db *DB) GetProperty(name string) (value string, err error) {
float64(read)/1048576.0, float64(write)/1048576.0)
}
case p == "sstables":
- for level, tables := range v.tables {
+ for level, tables := range v.levels {
value += fmt.Sprintf("--- level %d ---\n", level)
for _, t := range tables {
- value += fmt.Sprintf("%d:%d[%q .. %q]\n", t.file.Num(), t.size, t.imin, t.imax)
+ value += fmt.Sprintf("%d:%d[%q .. %q]\n", t.fd.Num, t.size, t.imin, t.imax)
}
}
case p == "blockpool":
@@ -837,7 +975,7 @@ func (db *DB) GetProperty(name string) (value string, err error) {
case p == "aliveiters":
value = fmt.Sprintf("%d", atomic.LoadInt32(&db.aliveIters))
default:
- err = errors.New("leveldb: GetProperty: unknown property: " + name)
+ err = ErrNotFound
}
return
@@ -859,8 +997,8 @@ func (db *DB) SizeOf(ranges []util.Range) (Sizes, error) {
sizes := make(Sizes, 0, len(ranges))
for _, r := range ranges {
- imin := newIkey(r.Start, kMaxSeq, ktSeek)
- imax := newIkey(r.Limit, kMaxSeq, ktSeek)
+ imin := makeIkey(nil, r.Start, kMaxSeq, ktSeek)
+ imax := makeIkey(nil, r.Limit, kMaxSeq, ktSeek)
start, err := v.offsetOf(imin)
if err != nil {
return nil, err
@@ -879,8 +1017,8 @@ func (db *DB) SizeOf(ranges []util.Range) (Sizes, error) {
return sizes, nil
}
-// Close closes the DB. This will also releases any outstanding snapshot and
-// abort any in-flight compaction.
+// Close closes the DB. This will also releases any outstanding snapshot,
+// abort any in-flight compaction and discard open transaction.
//
// It is not safe to close a DB until all outstanding iterators are released.
// It is valid to call Close multiple times. Other methods should not be
@@ -900,17 +1038,27 @@ func (db *DB) Close() error {
var err error
select {
case err = <-db.compErrC:
+ if err == ErrReadOnly {
+ err = nil
+ }
default:
}
// Signal all goroutines.
close(db.closeC)
+ // Discard open transaction.
+ if db.tr != nil {
+ db.tr.Discard()
+ }
+
+ // Acquire writer lock.
+ db.writeLockC <- struct{}{}
+
// Wait for all gorotines to exit.
db.closeW.Wait()
- // Lock writer and closes journal.
- db.writeLockC <- struct{}{}
+ // Closes journal.
if db.journal != nil {
db.journal.Close()
db.journalWriter.Close()
@@ -937,8 +1085,6 @@ func (db *DB) Close() error {
db.frozenMem = nil
db.journal = nil
db.journalWriter = nil
- db.journalFile = nil
- db.frozenJournalFile = nil
db.closer = nil
return err
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_compaction.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_compaction.go
index 447407aba..a94cf4c84 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_compaction.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_compaction.go
@@ -11,109 +11,79 @@ import (
"time"
"github.com/syndtr/goleveldb/leveldb/errors"
- "github.com/syndtr/goleveldb/leveldb/memdb"
"github.com/syndtr/goleveldb/leveldb/opt"
+ "github.com/syndtr/goleveldb/leveldb/storage"
)
var (
errCompactionTransactExiting = errors.New("leveldb: compaction transact exiting")
)
-type cStats struct {
- sync.Mutex
+type cStat struct {
duration time.Duration
- read uint64
- write uint64
+ read int64
+ write int64
}
-func (p *cStats) add(n *cStatsStaging) {
- p.Lock()
+func (p *cStat) add(n *cStatStaging) {
p.duration += n.duration
p.read += n.read
p.write += n.write
- p.Unlock()
}
-func (p *cStats) get() (duration time.Duration, read, write uint64) {
- p.Lock()
- defer p.Unlock()
+func (p *cStat) get() (duration time.Duration, read, write int64) {
return p.duration, p.read, p.write
}
-type cStatsStaging struct {
+type cStatStaging struct {
start time.Time
duration time.Duration
on bool
- read uint64
- write uint64
+ read int64
+ write int64
}
-func (p *cStatsStaging) startTimer() {
+func (p *cStatStaging) startTimer() {
if !p.on {
p.start = time.Now()
p.on = true
}
}
-func (p *cStatsStaging) stopTimer() {
+func (p *cStatStaging) stopTimer() {
if p.on {
p.duration += time.Since(p.start)
p.on = false
}
}
-type cMem struct {
- s *session
- level int
- rec *sessionRecord
-}
-
-func newCMem(s *session) *cMem {
- return &cMem{s: s, rec: &sessionRecord{numLevel: s.o.GetNumLevel()}}
+type cStats struct {
+ lk sync.Mutex
+ stats []cStat
}
-func (c *cMem) flush(mem *memdb.DB, level int) error {
- s := c.s
-
- // Write memdb to table.
- iter := mem.NewIterator(nil)
- defer iter.Release()
- t, n, err := s.tops.createFrom(iter)
- if err != nil {
- return err
- }
-
- // Pick level.
- if level < 0 {
- v := s.version()
- level = v.pickLevel(t.imin.ukey(), t.imax.ukey())
- v.release()
+func (p *cStats) addStat(level int, n *cStatStaging) {
+ p.lk.Lock()
+ if level >= len(p.stats) {
+ newStats := make([]cStat, level+1)
+ copy(newStats, p.stats)
+ p.stats = newStats
}
- c.rec.addTableFile(level, t)
-
- s.logf("mem@flush created L%d@%d N·%d S·%s %q:%q", level, t.file.Num(), n, shortenb(int(t.size)), t.imin, t.imax)
-
- c.level = level
- return nil
+ p.stats[level].add(n)
+ p.lk.Unlock()
}
-func (c *cMem) reset() {
- c.rec = &sessionRecord{numLevel: c.s.o.GetNumLevel()}
-}
-
-func (c *cMem) commit(journal, seq uint64) error {
- c.rec.setJournalNum(journal)
- c.rec.setSeqNum(seq)
-
- // Commit changes.
- return c.s.commit(c.rec)
+func (p *cStats) getStat(level int) (duration time.Duration, read, write int64) {
+ p.lk.Lock()
+ defer p.lk.Unlock()
+ if level < len(p.stats) {
+ return p.stats[level].get()
+ }
+ return
}
func (db *DB) compactionError() {
- var (
- err error
- wlocked bool
- )
+ var err error
noerr:
// No error.
for {
@@ -121,7 +91,7 @@ noerr:
case err = <-db.compErrSetC:
switch {
case err == nil:
- case errors.IsCorrupted(err):
+ case err == ErrReadOnly, errors.IsCorrupted(err):
goto hasperr
default:
goto haserr
@@ -139,7 +109,7 @@ haserr:
switch {
case err == nil:
goto noerr
- case errors.IsCorrupted(err):
+ case err == ErrReadOnly, errors.IsCorrupted(err):
goto hasperr
default:
}
@@ -155,9 +125,9 @@ hasperr:
case db.compPerErrC <- err:
case db.writeLockC <- struct{}{}:
// Hold write lock, so that write won't pass-through.
- wlocked = true
+ db.compWriteLocking = true
case _, _ = <-db.closeC:
- if wlocked {
+ if db.compWriteLocking {
// We should release the lock or Close will hang.
<-db.writeLockC
}
@@ -286,22 +256,27 @@ func (db *DB) compactionExitTransact() {
panic(errCompactionTransactExiting)
}
+func (db *DB) compactionCommit(name string, rec *sessionRecord) {
+ db.compCommitLk.Lock()
+ defer db.compCommitLk.Unlock() // Defer is necessary.
+ db.compactionTransactFunc(name+"@commit", func(cnt *compactionTransactCounter) error {
+ return db.s.commit(rec)
+ }, nil)
+}
+
func (db *DB) memCompaction() {
- mem := db.getFrozenMem()
- if mem == nil {
+ mdb := db.getFrozenMem()
+ if mdb == nil {
return
}
- defer mem.decref()
-
- c := newCMem(db.s)
- stats := new(cStatsStaging)
+ defer mdb.decref()
- db.logf("mem@flush N·%d S·%s", mem.mdb.Len(), shortenb(mem.mdb.Size()))
+ db.logf("memdb@flush N·%d S·%s", mdb.Len(), shortenb(mdb.Size()))
// Don't compact empty memdb.
- if mem.mdb.Len() == 0 {
- db.logf("mem@flush skipping")
- // drop frozen mem
+ if mdb.Len() == 0 {
+ db.logf("memdb@flush skipping")
+ // drop frozen memdb
db.dropFrozenMem()
return
}
@@ -317,35 +292,44 @@ func (db *DB) memCompaction() {
return
}
- db.compactionTransactFunc("mem@flush", func(cnt *compactionTransactCounter) (err error) {
+ var (
+ rec = &sessionRecord{}
+ stats = &cStatStaging{}
+ flushLevel int
+ )
+
+ // Generate tables.
+ db.compactionTransactFunc("memdb@flush", func(cnt *compactionTransactCounter) (err error) {
stats.startTimer()
- defer stats.stopTimer()
- return c.flush(mem.mdb, -1)
+ flushLevel, err = db.s.flushMemdb(rec, mdb.DB, db.memdbMaxLevel)
+ stats.stopTimer()
+ return
}, func() error {
- for _, r := range c.rec.addedTables {
- db.logf("mem@flush revert @%d", r.num)
- f := db.s.getTableFile(r.num)
- if err := f.Remove(); err != nil {
+ for _, r := range rec.addedTables {
+ db.logf("memdb@flush revert @%d", r.num)
+ if err := db.s.stor.Remove(storage.FileDesc{Type: storage.TypeTable, Num: r.num}); err != nil {
return err
}
}
return nil
})
- db.compactionTransactFunc("mem@commit", func(cnt *compactionTransactCounter) (err error) {
- stats.startTimer()
- defer stats.stopTimer()
- return c.commit(db.journalFile.Num(), db.frozenSeq)
- }, nil)
+ rec.setJournalNum(db.journalFd.Num)
+ rec.setSeqNum(db.frozenSeq)
+
+ // Commit.
+ stats.startTimer()
+ db.compactionCommit("memdb", rec)
+ stats.stopTimer()
- db.logf("mem@flush committed F·%d T·%v", len(c.rec.addedTables), stats.duration)
+ db.logf("memdb@flush committed F·%d T·%v", len(rec.addedTables), stats.duration)
- for _, r := range c.rec.addedTables {
+ for _, r := range rec.addedTables {
stats.write += r.size
}
- db.compStats[c.level].add(stats)
+ db.compStats.addStat(flushLevel, stats)
- // Drop frozen mem.
+ // Drop frozen memdb.
db.dropFrozenMem()
// Resume table compaction.
@@ -359,7 +343,7 @@ func (db *DB) memCompaction() {
}
// Trigger table compaction.
- db.compSendTrigger(db.tcompCmdC)
+ db.compTrigger(db.tcompCmdC)
}
type tableCompactionBuilder struct {
@@ -367,7 +351,7 @@ type tableCompactionBuilder struct {
s *session
c *compaction
rec *sessionRecord
- stat0, stat1 *cStatsStaging
+ stat0, stat1 *cStatStaging
snapHasLastUkey bool
snapLastUkey []byte
@@ -421,9 +405,9 @@ func (b *tableCompactionBuilder) flush() error {
if err != nil {
return err
}
- b.rec.addTableFile(b.c.level+1, t)
+ b.rec.addTableFile(b.c.sourceLevel+1, t)
b.stat1.write += t.size
- b.s.logf("table@build created L%d@%d N·%d S·%s %q:%q", b.c.level+1, t.file.Num(), b.tw.tw.EntriesLen(), shortenb(int(t.size)), t.imin, t.imax)
+ b.s.logf("table@build created L%d@%d N·%d S·%s %q:%q", b.c.sourceLevel+1, t.fd.Num, b.tw.tw.EntriesLen(), shortenb(int(t.size)), t.imin, t.imax)
b.tw = nil
return nil
}
@@ -546,8 +530,7 @@ func (b *tableCompactionBuilder) run(cnt *compactionTransactCounter) error {
func (b *tableCompactionBuilder) revert() error {
for _, at := range b.rec.addedTables {
b.s.logf("table@build revert @%d", at.num)
- f := b.s.getTableFile(at.num)
- if err := f.Remove(); err != nil {
+ if err := b.s.stor.Remove(storage.FileDesc{Type: storage.TypeTable, Num: at.num}); err != nil {
return err
}
}
@@ -557,31 +540,31 @@ func (b *tableCompactionBuilder) revert() error {
func (db *DB) tableCompaction(c *compaction, noTrivial bool) {
defer c.release()
- rec := &sessionRecord{numLevel: db.s.o.GetNumLevel()}
- rec.addCompPtr(c.level, c.imax)
+ rec := &sessionRecord{}
+ rec.addCompPtr(c.sourceLevel, c.imax)
if !noTrivial && c.trivial() {
- t := c.tables[0][0]
- db.logf("table@move L%d@%d -> L%d", c.level, t.file.Num(), c.level+1)
- rec.delTable(c.level, t.file.Num())
- rec.addTableFile(c.level+1, t)
+ t := c.levels[0][0]
+ db.logf("table@move L%d@%d -> L%d", c.sourceLevel, t.fd.Num, c.sourceLevel+1)
+ rec.delTable(c.sourceLevel, t.fd.Num)
+ rec.addTableFile(c.sourceLevel+1, t)
db.compactionTransactFunc("table@move", func(cnt *compactionTransactCounter) (err error) {
return db.s.commit(rec)
}, nil)
return
}
- var stats [2]cStatsStaging
- for i, tables := range c.tables {
+ var stats [2]cStatStaging
+ for i, tables := range c.levels {
for _, t := range tables {
stats[i].read += t.size
// Insert deleted tables into record
- rec.delTable(c.level+i, t.file.Num())
+ rec.delTable(c.sourceLevel+i, t.fd.Num)
}
}
sourceSize := int(stats[0].read + stats[1].read)
minSeq := db.minSeq()
- db.logf("table@compaction L%d·%d -> L%d·%d S·%s Q·%d", c.level, len(c.tables[0]), c.level+1, len(c.tables[1]), shortenb(sourceSize), minSeq)
+ db.logf("table@compaction L%d·%d -> L%d·%d S·%s Q·%d", c.sourceLevel, len(c.levels[0]), c.sourceLevel+1, len(c.levels[1]), shortenb(sourceSize), minSeq)
b := &tableCompactionBuilder{
db: db,
@@ -591,49 +574,60 @@ func (db *DB) tableCompaction(c *compaction, noTrivial bool) {
stat1: &stats[1],
minSeq: minSeq,
strict: db.s.o.GetStrict(opt.StrictCompaction),
- tableSize: db.s.o.GetCompactionTableSize(c.level + 1),
+ tableSize: db.s.o.GetCompactionTableSize(c.sourceLevel + 1),
}
db.compactionTransact("table@build", b)
- // Commit changes
- db.compactionTransactFunc("table@commit", func(cnt *compactionTransactCounter) (err error) {
- stats[1].startTimer()
- defer stats[1].stopTimer()
- return db.s.commit(rec)
- }, nil)
+ // Commit.
+ stats[1].startTimer()
+ db.compactionCommit("table", rec)
+ stats[1].stopTimer()
resultSize := int(stats[1].write)
db.logf("table@compaction committed F%s S%s Ke·%d D·%d T·%v", sint(len(rec.addedTables)-len(rec.deletedTables)), sshortenb(resultSize-sourceSize), b.kerrCnt, b.dropCnt, stats[1].duration)
// Save compaction stats
for i := range stats {
- db.compStats[c.level+1].add(&stats[i])
+ db.compStats.addStat(c.sourceLevel+1, &stats[i])
}
}
-func (db *DB) tableRangeCompaction(level int, umin, umax []byte) {
+func (db *DB) tableRangeCompaction(level int, umin, umax []byte) error {
db.logf("table@compaction range L%d %q:%q", level, umin, umax)
-
if level >= 0 {
- if c := db.s.getCompactionRange(level, umin, umax); c != nil {
+ if c := db.s.getCompactionRange(level, umin, umax, true); c != nil {
db.tableCompaction(c, true)
}
} else {
- v := db.s.version()
- m := 1
- for i, t := range v.tables[1:] {
- if t.overlaps(db.s.icmp, umin, umax, false) {
- m = i + 1
+ // Retry until nothing to compact.
+ for {
+ compacted := false
+
+ // Scan for maximum level with overlapped tables.
+ v := db.s.version()
+ m := 1
+ for i := m; i < len(v.levels); i++ {
+ tables := v.levels[i]
+ if tables.overlaps(db.s.icmp, umin, umax, false) {
+ m = i
+ }
}
- }
- v.release()
+ v.release()
- for level := 0; level < m; level++ {
- if c := db.s.getCompactionRange(level, umin, umax); c != nil {
- db.tableCompaction(c, true)
+ for level := 0; level < m; level++ {
+ if c := db.s.getCompactionRange(level, umin, umax, false); c != nil {
+ db.tableCompaction(c, true)
+ compacted = true
+ }
+ }
+
+ if !compacted {
+ break
}
}
}
+
+ return nil
}
func (db *DB) tableAutoCompaction() {
@@ -660,11 +654,11 @@ type cCmd interface {
ack(err error)
}
-type cIdle struct {
+type cAuto struct {
ackC chan<- error
}
-func (r cIdle) ack(err error) {
+func (r cAuto) ack(err error) {
if r.ackC != nil {
defer func() {
recover()
@@ -688,13 +682,21 @@ func (r cRange) ack(err error) {
}
}
+// This will trigger auto compaction but will not wait for it.
+func (db *DB) compTrigger(compC chan<- cCmd) {
+ select {
+ case compC <- cAuto{}:
+ default:
+ }
+}
+
// This will trigger auto compation and/or wait for all compaction to be done.
-func (db *DB) compSendIdle(compC chan<- cCmd) (err error) {
+func (db *DB) compTriggerWait(compC chan<- cCmd) (err error) {
ch := make(chan error)
defer close(ch)
// Send cmd.
select {
- case compC <- cIdle{ch}:
+ case compC <- cAuto{ch}:
case err = <-db.compErrC:
return
case _, _ = <-db.closeC:
@@ -710,16 +712,8 @@ func (db *DB) compSendIdle(compC chan<- cCmd) (err error) {
return err
}
-// This will trigger auto compaction but will not wait for it.
-func (db *DB) compSendTrigger(compC chan<- cCmd) {
- select {
- case compC <- cIdle{}:
- default:
- }
-}
-
// Send range compaction request.
-func (db *DB) compSendRange(compC chan<- cCmd, level int, min, max []byte) (err error) {
+func (db *DB) compTriggerRange(compC chan<- cCmd, level int, min, max []byte) (err error) {
ch := make(chan error)
defer close(ch)
// Send cmd.
@@ -759,7 +753,7 @@ func (db *DB) mCompaction() {
select {
case x = <-db.mcompCmdC:
switch x.(type) {
- case cIdle:
+ case cAuto:
db.memCompaction()
x.ack(nil)
x = nil
@@ -820,11 +814,10 @@ func (db *DB) tCompaction() {
}
if x != nil {
switch cmd := x.(type) {
- case cIdle:
+ case cAuto:
ackQ = append(ackQ, x)
case cRange:
- db.tableRangeCompaction(cmd.level, cmd.min, cmd.max)
- x.ack(nil)
+ x.ack(db.tableRangeCompaction(cmd.level, cmd.min, cmd.max))
default:
panic("leveldb: unknown command")
}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_iter.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_iter.go
index 011a94a35..86bcb99d9 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_iter.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_iter.go
@@ -33,40 +33,50 @@ func (mr *memdbReleaser) Release() {
})
}
-func (db *DB) newRawIterator(slice *util.Range, ro *opt.ReadOptions) iterator.Iterator {
+func (db *DB) newRawIterator(auxm *memDB, auxt tFiles, slice *util.Range, ro *opt.ReadOptions) iterator.Iterator {
+ strict := opt.GetStrict(db.s.o.Options, ro, opt.StrictReader)
em, fm := db.getMems()
v := db.s.version()
- ti := v.getIterators(slice, ro)
- n := len(ti) + 2
- i := make([]iterator.Iterator, 0, n)
- emi := em.mdb.NewIterator(slice)
+ tableIts := v.getIterators(slice, ro)
+ n := len(tableIts) + len(auxt) + 3
+ its := make([]iterator.Iterator, 0, n)
+
+ if auxm != nil {
+ ami := auxm.NewIterator(slice)
+ ami.SetReleaser(&memdbReleaser{m: auxm})
+ its = append(its, ami)
+ }
+ for _, t := range auxt {
+ its = append(its, v.s.tops.newIterator(t, slice, ro))
+ }
+
+ emi := em.NewIterator(slice)
emi.SetReleaser(&memdbReleaser{m: em})
- i = append(i, emi)
+ its = append(its, emi)
if fm != nil {
- fmi := fm.mdb.NewIterator(slice)
+ fmi := fm.NewIterator(slice)
fmi.SetReleaser(&memdbReleaser{m: fm})
- i = append(i, fmi)
+ its = append(its, fmi)
}
- i = append(i, ti...)
- strict := opt.GetStrict(db.s.o.Options, ro, opt.StrictReader)
- mi := iterator.NewMergedIterator(i, db.s.icmp, strict)
+ its = append(its, tableIts...)
+ mi := iterator.NewMergedIterator(its, db.s.icmp, strict)
mi.SetReleaser(&versionReleaser{v: v})
return mi
}
-func (db *DB) newIterator(seq uint64, slice *util.Range, ro *opt.ReadOptions) *dbIter {
+func (db *DB) newIterator(auxm *memDB, auxt tFiles, seq uint64, slice *util.Range, ro *opt.ReadOptions) *dbIter {
var islice *util.Range
if slice != nil {
islice = &util.Range{}
if slice.Start != nil {
- islice.Start = newIkey(slice.Start, kMaxSeq, ktSeek)
+ islice.Start = makeIkey(nil, slice.Start, kMaxSeq, ktSeek)
}
if slice.Limit != nil {
- islice.Limit = newIkey(slice.Limit, kMaxSeq, ktSeek)
+ islice.Limit = makeIkey(nil, slice.Limit, kMaxSeq, ktSeek)
}
}
- rawIter := db.newRawIterator(islice, ro)
+ rawIter := db.newRawIterator(auxm, auxt, islice, ro)
iter := &dbIter{
db: db,
icmp: db.s.icmp,
@@ -177,7 +187,7 @@ func (i *dbIter) Seek(key []byte) bool {
return false
}
- ikey := newIkey(key, i.seq, ktSeek)
+ ikey := makeIkey(nil, key, i.seq, ktSeek)
if i.iter.Seek(ikey) {
i.dir = dirSOI
return i.next()
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_snapshot.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_snapshot.go
index 0372848ff..977f65ba5 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_snapshot.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_snapshot.go
@@ -110,7 +110,7 @@ func (snap *Snapshot) Get(key []byte, ro *opt.ReadOptions) (value []byte, err er
err = ErrSnapshotReleased
return
}
- return snap.db.get(key, snap.elem.seq, ro)
+ return snap.db.get(nil, nil, key, snap.elem.seq, ro)
}
// Has returns true if the DB does contains the given key.
@@ -127,10 +127,10 @@ func (snap *Snapshot) Has(key []byte, ro *opt.ReadOptions) (ret bool, err error)
err = ErrSnapshotReleased
return
}
- return snap.db.has(key, snap.elem.seq, ro)
+ return snap.db.has(nil, nil, key, snap.elem.seq, ro)
}
-// NewIterator returns an iterator for the snapshot of the uderlying DB.
+// NewIterator returns an iterator for the snapshot of the underlying DB.
// The returned iterator is not goroutine-safe, but it is safe to use
// multiple iterators concurrently, with each in a dedicated goroutine.
// It is also safe to use an iterator concurrently with modifying its
@@ -158,7 +158,7 @@ func (snap *Snapshot) NewIterator(slice *util.Range, ro *opt.ReadOptions) iterat
}
// Since iterator already hold version ref, it doesn't need to
// hold snapshot ref.
- return snap.db.newIterator(snap.elem.seq, slice, ro)
+ return snap.db.newIterator(nil, nil, snap.elem.seq, slice, ro)
}
// Release releases the snapshot. This will not release any returned
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_state.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_state.go
index d4db9d6dd..0207e221e 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_state.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_state.go
@@ -12,14 +12,19 @@ import (
"github.com/syndtr/goleveldb/leveldb/journal"
"github.com/syndtr/goleveldb/leveldb/memdb"
+ "github.com/syndtr/goleveldb/leveldb/storage"
)
type memDB struct {
- db *DB
- mdb *memdb.DB
+ db *DB
+ *memdb.DB
ref int32
}
+func (m *memDB) getref() int32 {
+ return atomic.LoadInt32(&m.ref)
+}
+
func (m *memDB) incref() {
atomic.AddInt32(&m.ref, 1)
}
@@ -27,12 +32,12 @@ func (m *memDB) incref() {
func (m *memDB) decref() {
if ref := atomic.AddInt32(&m.ref, -1); ref == 0 {
// Only put back memdb with std capacity.
- if m.mdb.Capacity() == m.db.s.o.GetWriteBuffer() {
- m.mdb.Reset()
- m.db.mpoolPut(m.mdb)
+ if m.Capacity() == m.db.s.o.GetWriteBuffer() {
+ m.Reset()
+ m.db.mpoolPut(m.DB)
}
m.db = nil
- m.mdb = nil
+ m.DB = nil
} else if ref < 0 {
panic("negative memdb ref")
}
@@ -48,11 +53,15 @@ func (db *DB) addSeq(delta uint64) {
atomic.AddUint64(&db.seq, delta)
}
+func (db *DB) setSeq(seq uint64) {
+ atomic.StoreUint64(&db.seq, seq)
+}
+
func (db *DB) sampleSeek(ikey iKey) {
v := db.s.version()
if v.sampleSeek(ikey) {
// Trigger table compaction.
- db.compSendTrigger(db.tcompCmdC)
+ db.compTrigger(db.tcompCmdC)
}
v.release()
}
@@ -67,12 +76,18 @@ func (db *DB) mpoolPut(mem *memdb.DB) {
}
}
-func (db *DB) mpoolGet() *memdb.DB {
+func (db *DB) mpoolGet(n int) *memDB {
+ var mdb *memdb.DB
select {
- case mem := <-db.memPool:
- return mem
+ case mdb = <-db.memPool:
default:
- return nil
+ }
+ if mdb == nil || mdb.Capacity() < n {
+ mdb = memdb.New(db.s.icmp, maxInt(db.s.o.GetWriteBuffer(), n))
+ }
+ return &memDB{
+ db: db,
+ DB: mdb,
}
}
@@ -95,11 +110,10 @@ func (db *DB) mpoolDrain() {
// Create new memdb and froze the old one; need external synchronization.
// newMem only called synchronously by the writer.
func (db *DB) newMem(n int) (mem *memDB, err error) {
- num := db.s.allocFileNum()
- file := db.s.getJournalFile(num)
- w, err := file.Create()
+ fd := storage.FileDesc{Type: storage.TypeJournal, Num: db.s.allocFileNum()}
+ w, err := db.s.stor.Create(fd)
if err != nil {
- db.s.reuseFileNum(num)
+ db.s.reuseFileNum(fd.Num)
return
}
@@ -115,20 +129,14 @@ func (db *DB) newMem(n int) (mem *memDB, err error) {
} else {
db.journal.Reset(w)
db.journalWriter.Close()
- db.frozenJournalFile = db.journalFile
+ db.frozenJournalFd = db.journalFd
}
db.journalWriter = w
- db.journalFile = file
+ db.journalFd = fd
db.frozenMem = db.mem
- mdb := db.mpoolGet()
- if mdb == nil || mdb.Capacity() < n {
- mdb = memdb.New(db.s.icmp, maxInt(db.s.o.GetWriteBuffer(), n))
- }
- mem = &memDB{
- db: db,
- mdb: mdb,
- ref: 2,
- }
+ mem = db.mpoolGet(n)
+ mem.incref() // for self
+ mem.incref() // for caller
db.mem = mem
// The seq only incremented by the writer. And whoever called newMem
// should hold write lock, so no need additional synchronization here.
@@ -181,12 +189,12 @@ func (db *DB) getFrozenMem() *memDB {
// Drop frozen memdb; assume that frozen memdb isn't nil.
func (db *DB) dropFrozenMem() {
db.memMu.Lock()
- if err := db.frozenJournalFile.Remove(); err != nil {
- db.logf("journal@remove removing @%d %q", db.frozenJournalFile.Num(), err)
+ if err := db.s.stor.Remove(db.frozenJournalFd); err != nil {
+ db.logf("journal@remove removing @%d %q", db.frozenJournalFd.Num, err)
} else {
- db.logf("journal@remove removed @%d", db.frozenJournalFile.Num())
+ db.logf("journal@remove removed @%d", db.frozenJournalFd.Num)
}
- db.frozenJournalFile = nil
+ db.frozenJournalFd = storage.FileDesc{}
db.frozenMem.decref()
db.frozenMem = nil
db.memMu.Unlock()
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_test.go
deleted file mode 100644
index 38bfbf1ea..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_test.go
+++ /dev/null
@@ -1,2665 +0,0 @@
-// Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
-// All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package leveldb
-
-import (
- "bytes"
- "container/list"
- crand "crypto/rand"
- "encoding/binary"
- "fmt"
- "math/rand"
- "os"
- "path/filepath"
- "runtime"
- "strings"
- "sync"
- "sync/atomic"
- "testing"
- "time"
- "unsafe"
-
- "github.com/syndtr/goleveldb/leveldb/comparer"
- "github.com/syndtr/goleveldb/leveldb/errors"
- "github.com/syndtr/goleveldb/leveldb/filter"
- "github.com/syndtr/goleveldb/leveldb/iterator"
- "github.com/syndtr/goleveldb/leveldb/opt"
- "github.com/syndtr/goleveldb/leveldb/storage"
- "github.com/syndtr/goleveldb/leveldb/util"
-)
-
-func tkey(i int) []byte {
- return []byte(fmt.Sprintf("%016d", i))
-}
-
-func tval(seed, n int) []byte {
- r := rand.New(rand.NewSource(int64(seed)))
- return randomString(r, n)
-}
-
-type dbHarness struct {
- t *testing.T
-
- stor *testStorage
- db *DB
- o *opt.Options
- ro *opt.ReadOptions
- wo *opt.WriteOptions
-}
-
-func newDbHarnessWopt(t *testing.T, o *opt.Options) *dbHarness {
- h := new(dbHarness)
- h.init(t, o)
- return h
-}
-
-func newDbHarness(t *testing.T) *dbHarness {
- return newDbHarnessWopt(t, &opt.Options{})
-}
-
-func (h *dbHarness) init(t *testing.T, o *opt.Options) {
- h.t = t
- h.stor = newTestStorage(t)
- h.o = o
- h.ro = nil
- h.wo = nil
-
- if err := h.openDB0(); err != nil {
- // So that it will come after fatal message.
- defer h.stor.Close()
- h.t.Fatal("Open (init): got error: ", err)
- }
-}
-
-func (h *dbHarness) openDB0() (err error) {
- h.t.Log("opening DB")
- h.db, err = Open(h.stor, h.o)
- return
-}
-
-func (h *dbHarness) openDB() {
- if err := h.openDB0(); err != nil {
- h.t.Fatal("Open: got error: ", err)
- }
-}
-
-func (h *dbHarness) closeDB0() error {
- h.t.Log("closing DB")
- return h.db.Close()
-}
-
-func (h *dbHarness) closeDB() {
- if err := h.closeDB0(); err != nil {
- h.t.Error("Close: got error: ", err)
- }
- h.stor.CloseCheck()
- runtime.GC()
-}
-
-func (h *dbHarness) reopenDB() {
- h.closeDB()
- h.openDB()
-}
-
-func (h *dbHarness) close() {
- h.closeDB0()
- h.db = nil
- h.stor.Close()
- h.stor = nil
- runtime.GC()
-}
-
-func (h *dbHarness) openAssert(want bool) {
- db, err := Open(h.stor, h.o)
- if err != nil {
- if want {
- h.t.Error("Open: assert: got error: ", err)
- } else {
- h.t.Log("Open: assert: got error (expected): ", err)
- }
- } else {
- if !want {
- h.t.Error("Open: assert: expect error")
- }
- db.Close()
- }
-}
-
-func (h *dbHarness) write(batch *Batch) {
- if err := h.db.Write(batch, h.wo); err != nil {
- h.t.Error("Write: got error: ", err)
- }
-}
-
-func (h *dbHarness) put(key, value string) {
- if err := h.db.Put([]byte(key), []byte(value), h.wo); err != nil {
- h.t.Error("Put: got error: ", err)
- }
-}
-
-func (h *dbHarness) putMulti(n int, low, hi string) {
- for i := 0; i < n; i++ {
- h.put(low, "begin")
- h.put(hi, "end")
- h.compactMem()
- }
-}
-
-func (h *dbHarness) maxNextLevelOverlappingBytes(want uint64) {
- t := h.t
- db := h.db
-
- var (
- maxOverlaps uint64
- maxLevel int
- )
- v := db.s.version()
- for i, tt := range v.tables[1 : len(v.tables)-1] {
- level := i + 1
- next := v.tables[level+1]
- for _, t := range tt {
- r := next.getOverlaps(nil, db.s.icmp, t.imin.ukey(), t.imax.ukey(), false)
- sum := r.size()
- if sum > maxOverlaps {
- maxOverlaps = sum
- maxLevel = level
- }
- }
- }
- v.release()
-
- if maxOverlaps > want {
- t.Errorf("next level most overlapping bytes is more than %d, got=%d level=%d", want, maxOverlaps, maxLevel)
- } else {
- t.Logf("next level most overlapping bytes is %d, level=%d want=%d", maxOverlaps, maxLevel, want)
- }
-}
-
-func (h *dbHarness) delete(key string) {
- t := h.t
- db := h.db
-
- err := db.Delete([]byte(key), h.wo)
- if err != nil {
- t.Error("Delete: got error: ", err)
- }
-}
-
-func (h *dbHarness) assertNumKeys(want int) {
- iter := h.db.NewIterator(nil, h.ro)
- defer iter.Release()
- got := 0
- for iter.Next() {
- got++
- }
- if err := iter.Error(); err != nil {
- h.t.Error("assertNumKeys: ", err)
- }
- if want != got {
- h.t.Errorf("assertNumKeys: want=%d got=%d", want, got)
- }
-}
-
-func (h *dbHarness) getr(db Reader, key string, expectFound bool) (found bool, v []byte) {
- t := h.t
- v, err := db.Get([]byte(key), h.ro)
- switch err {
- case ErrNotFound:
- if expectFound {
- t.Errorf("Get: key '%s' not found, want found", key)
- }
- case nil:
- found = true
- if !expectFound {
- t.Errorf("Get: key '%s' found, want not found", key)
- }
- default:
- t.Error("Get: got error: ", err)
- }
- return
-}
-
-func (h *dbHarness) get(key string, expectFound bool) (found bool, v []byte) {
- return h.getr(h.db, key, expectFound)
-}
-
-func (h *dbHarness) getValr(db Reader, key, value string) {
- t := h.t
- found, r := h.getr(db, key, true)
- if !found {
- return
- }
- rval := string(r)
- if rval != value {
- t.Errorf("Get: invalid value, got '%s', want '%s'", rval, value)
- }
-}
-
-func (h *dbHarness) getVal(key, value string) {
- h.getValr(h.db, key, value)
-}
-
-func (h *dbHarness) allEntriesFor(key, want string) {
- t := h.t
- db := h.db
- s := db.s
-
- ikey := newIkey([]byte(key), kMaxSeq, ktVal)
- iter := db.newRawIterator(nil, nil)
- if !iter.Seek(ikey) && iter.Error() != nil {
- t.Error("AllEntries: error during seek, err: ", iter.Error())
- return
- }
- res := "[ "
- first := true
- for iter.Valid() {
- if ukey, _, kt, kerr := parseIkey(iter.Key()); kerr == nil {
- if s.icmp.uCompare(ikey.ukey(), ukey) != 0 {
- break
- }
- if !first {
- res += ", "
- }
- first = false
- switch kt {
- case ktVal:
- res += string(iter.Value())
- case ktDel:
- res += "DEL"
- }
- } else {
- if !first {
- res += ", "
- }
- first = false
- res += "CORRUPTED"
- }
- iter.Next()
- }
- if !first {
- res += " "
- }
- res += "]"
- if res != want {
- t.Errorf("AllEntries: assert failed for key %q, got=%q want=%q", key, res, want)
- }
-}
-
-// Return a string that contains all key,value pairs in order,
-// formatted like "(k1->v1)(k2->v2)".
-func (h *dbHarness) getKeyVal(want string) {
- t := h.t
- db := h.db
-
- s, err := db.GetSnapshot()
- if err != nil {
- t.Fatal("GetSnapshot: got error: ", err)
- }
- res := ""
- iter := s.NewIterator(nil, nil)
- for iter.Next() {
- res += fmt.Sprintf("(%s->%s)", string(iter.Key()), string(iter.Value()))
- }
- iter.Release()
-
- if res != want {
- t.Errorf("GetKeyVal: invalid key/value pair, got=%q want=%q", res, want)
- }
- s.Release()
-}
-
-func (h *dbHarness) waitCompaction() {
- t := h.t
- db := h.db
- if err := db.compSendIdle(db.tcompCmdC); err != nil {
- t.Error("compaction error: ", err)
- }
-}
-
-func (h *dbHarness) waitMemCompaction() {
- t := h.t
- db := h.db
-
- if err := db.compSendIdle(db.mcompCmdC); err != nil {
- t.Error("compaction error: ", err)
- }
-}
-
-func (h *dbHarness) compactMem() {
- t := h.t
- db := h.db
-
- t.Log("starting memdb compaction")
-
- db.writeLockC <- struct{}{}
- defer func() {
- <-db.writeLockC
- }()
-
- if _, err := db.rotateMem(0); err != nil {
- t.Error("compaction error: ", err)
- }
- if err := db.compSendIdle(db.mcompCmdC); err != nil {
- t.Error("compaction error: ", err)
- }
-
- if h.totalTables() == 0 {
- t.Error("zero tables after mem compaction")
- }
-
- t.Log("memdb compaction done")
-}
-
-func (h *dbHarness) compactRangeAtErr(level int, min, max string, wanterr bool) {
- t := h.t
- db := h.db
-
- var _min, _max []byte
- if min != "" {
- _min = []byte(min)
- }
- if max != "" {
- _max = []byte(max)
- }
-
- t.Logf("starting table range compaction: level=%d, min=%q, max=%q", level, min, max)
-
- if err := db.compSendRange(db.tcompCmdC, level, _min, _max); err != nil {
- if wanterr {
- t.Log("CompactRangeAt: got error (expected): ", err)
- } else {
- t.Error("CompactRangeAt: got error: ", err)
- }
- } else if wanterr {
- t.Error("CompactRangeAt: expect error")
- }
-
- t.Log("table range compaction done")
-}
-
-func (h *dbHarness) compactRangeAt(level int, min, max string) {
- h.compactRangeAtErr(level, min, max, false)
-}
-
-func (h *dbHarness) compactRange(min, max string) {
- t := h.t
- db := h.db
-
- t.Logf("starting DB range compaction: min=%q, max=%q", min, max)
-
- var r util.Range
- if min != "" {
- r.Start = []byte(min)
- }
- if max != "" {
- r.Limit = []byte(max)
- }
- if err := db.CompactRange(r); err != nil {
- t.Error("CompactRange: got error: ", err)
- }
-
- t.Log("DB range compaction done")
-}
-
-func (h *dbHarness) sizeOf(start, limit string) uint64 {
- sz, err := h.db.SizeOf([]util.Range{
- {[]byte(start), []byte(limit)},
- })
- if err != nil {
- h.t.Error("SizeOf: got error: ", err)
- }
- return sz.Sum()
-}
-
-func (h *dbHarness) sizeAssert(start, limit string, low, hi uint64) {
- sz := h.sizeOf(start, limit)
- if sz < low || sz > hi {
- h.t.Errorf("sizeOf %q to %q not in range, want %d - %d, got %d",
- shorten(start), shorten(limit), low, hi, sz)
- }
-}
-
-func (h *dbHarness) getSnapshot() (s *Snapshot) {
- s, err := h.db.GetSnapshot()
- if err != nil {
- h.t.Fatal("GetSnapshot: got error: ", err)
- }
- return
-}
-func (h *dbHarness) tablesPerLevel(want string) {
- res := ""
- nz := 0
- v := h.db.s.version()
- for level, tt := range v.tables {
- if level > 0 {
- res += ","
- }
- res += fmt.Sprint(len(tt))
- if len(tt) > 0 {
- nz = len(res)
- }
- }
- v.release()
- res = res[:nz]
- if res != want {
- h.t.Errorf("invalid tables len, want=%s, got=%s", want, res)
- }
-}
-
-func (h *dbHarness) totalTables() (n int) {
- v := h.db.s.version()
- for _, tt := range v.tables {
- n += len(tt)
- }
- v.release()
- return
-}
-
-type keyValue interface {
- Key() []byte
- Value() []byte
-}
-
-func testKeyVal(t *testing.T, kv keyValue, want string) {
- res := string(kv.Key()) + "->" + string(kv.Value())
- if res != want {
- t.Errorf("invalid key/value, want=%q, got=%q", want, res)
- }
-}
-
-func numKey(num int) string {
- return fmt.Sprintf("key%06d", num)
-}
-
-var _bloom_filter = filter.NewBloomFilter(10)
-
-func truno(t *testing.T, o *opt.Options, f func(h *dbHarness)) {
- for i := 0; i < 4; i++ {
- func() {
- switch i {
- case 0:
- case 1:
- if o == nil {
- o = &opt.Options{Filter: _bloom_filter}
- } else {
- old := o
- o = &opt.Options{}
- *o = *old
- o.Filter = _bloom_filter
- }
- case 2:
- if o == nil {
- o = &opt.Options{Compression: opt.NoCompression}
- } else {
- old := o
- o = &opt.Options{}
- *o = *old
- o.Compression = opt.NoCompression
- }
- }
- h := newDbHarnessWopt(t, o)
- defer h.close()
- switch i {
- case 3:
- h.reopenDB()
- }
- f(h)
- }()
- }
-}
-
-func trun(t *testing.T, f func(h *dbHarness)) {
- truno(t, nil, f)
-}
-
-func testAligned(t *testing.T, name string, offset uintptr) {
- if offset%8 != 0 {
- t.Errorf("field %s offset is not 64-bit aligned", name)
- }
-}
-
-func Test_FieldsAligned(t *testing.T) {
- p1 := new(DB)
- testAligned(t, "DB.seq", unsafe.Offsetof(p1.seq))
- p2 := new(session)
- testAligned(t, "session.stNextFileNum", unsafe.Offsetof(p2.stNextFileNum))
- testAligned(t, "session.stJournalNum", unsafe.Offsetof(p2.stJournalNum))
- testAligned(t, "session.stPrevJournalNum", unsafe.Offsetof(p2.stPrevJournalNum))
- testAligned(t, "session.stSeqNum", unsafe.Offsetof(p2.stSeqNum))
-}
-
-func TestDB_Locking(t *testing.T) {
- h := newDbHarness(t)
- defer h.stor.Close()
- h.openAssert(false)
- h.closeDB()
- h.openAssert(true)
-}
-
-func TestDB_Empty(t *testing.T) {
- trun(t, func(h *dbHarness) {
- h.get("foo", false)
-
- h.reopenDB()
- h.get("foo", false)
- })
-}
-
-func TestDB_ReadWrite(t *testing.T) {
- trun(t, func(h *dbHarness) {
- h.put("foo", "v1")
- h.getVal("foo", "v1")
- h.put("bar", "v2")
- h.put("foo", "v3")
- h.getVal("foo", "v3")
- h.getVal("bar", "v2")
-
- h.reopenDB()
- h.getVal("foo", "v3")
- h.getVal("bar", "v2")
- })
-}
-
-func TestDB_PutDeleteGet(t *testing.T) {
- trun(t, func(h *dbHarness) {
- h.put("foo", "v1")
- h.getVal("foo", "v1")
- h.put("foo", "v2")
- h.getVal("foo", "v2")
- h.delete("foo")
- h.get("foo", false)
-
- h.reopenDB()
- h.get("foo", false)
- })
-}
-
-func TestDB_EmptyBatch(t *testing.T) {
- h := newDbHarness(t)
- defer h.close()
-
- h.get("foo", false)
- err := h.db.Write(new(Batch), h.wo)
- if err != nil {
- t.Error("writing empty batch yield error: ", err)
- }
- h.get("foo", false)
-}
-
-func TestDB_GetFromFrozen(t *testing.T) {
- h := newDbHarnessWopt(t, &opt.Options{WriteBuffer: 100100})
- defer h.close()
-
- h.put("foo", "v1")
- h.getVal("foo", "v1")
-
- h.stor.DelaySync(storage.TypeTable) // Block sync calls
- h.put("k1", strings.Repeat("x", 100000)) // Fill memtable
- h.put("k2", strings.Repeat("y", 100000)) // Trigger compaction
- for i := 0; h.db.getFrozenMem() == nil && i < 100; i++ {
- time.Sleep(10 * time.Microsecond)
- }
- if h.db.getFrozenMem() == nil {
- h.stor.ReleaseSync(storage.TypeTable)
- t.Fatal("No frozen mem")
- }
- h.getVal("foo", "v1")
- h.stor.ReleaseSync(storage.TypeTable) // Release sync calls
-
- h.reopenDB()
- h.getVal("foo", "v1")
- h.get("k1", true)
- h.get("k2", true)
-}
-
-func TestDB_GetFromTable(t *testing.T) {
- trun(t, func(h *dbHarness) {
- h.put("foo", "v1")
- h.compactMem()
- h.getVal("foo", "v1")
- })
-}
-
-func TestDB_GetSnapshot(t *testing.T) {
- trun(t, func(h *dbHarness) {
- bar := strings.Repeat("b", 200)
- h.put("foo", "v1")
- h.put(bar, "v1")
-
- snap, err := h.db.GetSnapshot()
- if err != nil {
- t.Fatal("GetSnapshot: got error: ", err)
- }
-
- h.put("foo", "v2")
- h.put(bar, "v2")
-
- h.getVal("foo", "v2")
- h.getVal(bar, "v2")
- h.getValr(snap, "foo", "v1")
- h.getValr(snap, bar, "v1")
-
- h.compactMem()
-
- h.getVal("foo", "v2")
- h.getVal(bar, "v2")
- h.getValr(snap, "foo", "v1")
- h.getValr(snap, bar, "v1")
-
- snap.Release()
-
- h.reopenDB()
- h.getVal("foo", "v2")
- h.getVal(bar, "v2")
- })
-}
-
-func TestDB_GetLevel0Ordering(t *testing.T) {
- trun(t, func(h *dbHarness) {
- for i := 0; i < 4; i++ {
- h.put("bar", fmt.Sprintf("b%d", i))
- h.put("foo", fmt.Sprintf("v%d", i))
- h.compactMem()
- }
- h.getVal("foo", "v3")
- h.getVal("bar", "b3")
-
- v := h.db.s.version()
- t0len := v.tLen(0)
- v.release()
- if t0len < 2 {
- t.Errorf("level-0 tables is less than 2, got %d", t0len)
- }
-
- h.reopenDB()
- h.getVal("foo", "v3")
- h.getVal("bar", "b3")
- })
-}
-
-func TestDB_GetOrderedByLevels(t *testing.T) {
- trun(t, func(h *dbHarness) {
- h.put("foo", "v1")
- h.compactMem()
- h.compactRange("a", "z")
- h.getVal("foo", "v1")
- h.put("foo", "v2")
- h.compactMem()
- h.getVal("foo", "v2")
- })
-}
-
-func TestDB_GetPicksCorrectFile(t *testing.T) {
- trun(t, func(h *dbHarness) {
- // Arrange to have multiple files in a non-level-0 level.
- h.put("a", "va")
- h.compactMem()
- h.compactRange("a", "b")
- h.put("x", "vx")
- h.compactMem()
- h.compactRange("x", "y")
- h.put("f", "vf")
- h.compactMem()
- h.compactRange("f", "g")
-
- h.getVal("a", "va")
- h.getVal("f", "vf")
- h.getVal("x", "vx")
-
- h.compactRange("", "")
- h.getVal("a", "va")
- h.getVal("f", "vf")
- h.getVal("x", "vx")
- })
-}
-
-func TestDB_GetEncountersEmptyLevel(t *testing.T) {
- trun(t, func(h *dbHarness) {
- // Arrange for the following to happen:
- // * sstable A in level 0
- // * nothing in level 1
- // * sstable B in level 2
- // Then do enough Get() calls to arrange for an automatic compaction
- // of sstable A. A bug would cause the compaction to be marked as
- // occuring at level 1 (instead of the correct level 0).
-
- // Step 1: First place sstables in levels 0 and 2
- for i := 0; ; i++ {
- if i >= 100 {
- t.Fatal("could not fill levels-0 and level-2")
- }
- v := h.db.s.version()
- if v.tLen(0) > 0 && v.tLen(2) > 0 {
- v.release()
- break
- }
- v.release()
- h.put("a", "begin")
- h.put("z", "end")
- h.compactMem()
-
- h.getVal("a", "begin")
- h.getVal("z", "end")
- }
-
- // Step 2: clear level 1 if necessary.
- h.compactRangeAt(1, "", "")
- h.tablesPerLevel("1,0,1")
-
- h.getVal("a", "begin")
- h.getVal("z", "end")
-
- // Step 3: read a bunch of times
- for i := 0; i < 200; i++ {
- h.get("missing", false)
- }
-
- // Step 4: Wait for compaction to finish
- h.waitCompaction()
-
- v := h.db.s.version()
- if v.tLen(0) > 0 {
- t.Errorf("level-0 tables more than 0, got %d", v.tLen(0))
- }
- v.release()
-
- h.getVal("a", "begin")
- h.getVal("z", "end")
- })
-}
-
-func TestDB_IterMultiWithDelete(t *testing.T) {
- trun(t, func(h *dbHarness) {
- h.put("a", "va")
- h.put("b", "vb")
- h.put("c", "vc")
- h.delete("b")
- h.get("b", false)
-
- iter := h.db.NewIterator(nil, nil)
- iter.Seek([]byte("c"))
- testKeyVal(t, iter, "c->vc")
- iter.Prev()
- testKeyVal(t, iter, "a->va")
- iter.Release()
-
- h.compactMem()
-
- iter = h.db.NewIterator(nil, nil)
- iter.Seek([]byte("c"))
- testKeyVal(t, iter, "c->vc")
- iter.Prev()
- testKeyVal(t, iter, "a->va")
- iter.Release()
- })
-}
-
-func TestDB_IteratorPinsRef(t *testing.T) {
- h := newDbHarness(t)
- defer h.close()
-
- h.put("foo", "hello")
-
- // Get iterator that will yield the current contents of the DB.
- iter := h.db.NewIterator(nil, nil)
-
- // Write to force compactions
- h.put("foo", "newvalue1")
- for i := 0; i < 100; i++ {
- h.put(numKey(i), strings.Repeat(fmt.Sprintf("v%09d", i), 100000/10))
- }
- h.put("foo", "newvalue2")
-
- iter.First()
- testKeyVal(t, iter, "foo->hello")
- if iter.Next() {
- t.Errorf("expect eof")
- }
- iter.Release()
-}
-
-func TestDB_Recover(t *testing.T) {
- trun(t, func(h *dbHarness) {
- h.put("foo", "v1")
- h.put("baz", "v5")
-
- h.reopenDB()
- h.getVal("foo", "v1")
-
- h.getVal("foo", "v1")
- h.getVal("baz", "v5")
- h.put("bar", "v2")
- h.put("foo", "v3")
-
- h.reopenDB()
- h.getVal("foo", "v3")
- h.put("foo", "v4")
- h.getVal("foo", "v4")
- h.getVal("bar", "v2")
- h.getVal("baz", "v5")
- })
-}
-
-func TestDB_RecoverWithEmptyJournal(t *testing.T) {
- trun(t, func(h *dbHarness) {
- h.put("foo", "v1")
- h.put("foo", "v2")
-
- h.reopenDB()
- h.reopenDB()
- h.put("foo", "v3")
-
- h.reopenDB()
- h.getVal("foo", "v3")
- })
-}
-
-func TestDB_RecoverDuringMemtableCompaction(t *testing.T) {
- truno(t, &opt.Options{WriteBuffer: 1000000}, func(h *dbHarness) {
-
- h.stor.DelaySync(storage.TypeTable)
- h.put("big1", strings.Repeat("x", 10000000))
- h.put("big2", strings.Repeat("y", 1000))
- h.put("bar", "v2")
- h.stor.ReleaseSync(storage.TypeTable)
-
- h.reopenDB()
- h.getVal("bar", "v2")
- h.getVal("big1", strings.Repeat("x", 10000000))
- h.getVal("big2", strings.Repeat("y", 1000))
- })
-}
-
-func TestDB_MinorCompactionsHappen(t *testing.T) {
- h := newDbHarnessWopt(t, &opt.Options{WriteBuffer: 10000})
- defer h.close()
-
- n := 500
-
- key := func(i int) string {
- return fmt.Sprintf("key%06d", i)
- }
-
- for i := 0; i < n; i++ {
- h.put(key(i), key(i)+strings.Repeat("v", 1000))
- }
-
- for i := 0; i < n; i++ {
- h.getVal(key(i), key(i)+strings.Repeat("v", 1000))
- }
-
- h.reopenDB()
- for i := 0; i < n; i++ {
- h.getVal(key(i), key(i)+strings.Repeat("v", 1000))
- }
-}
-
-func TestDB_RecoverWithLargeJournal(t *testing.T) {
- h := newDbHarness(t)
- defer h.close()
-
- h.put("big1", strings.Repeat("1", 200000))
- h.put("big2", strings.Repeat("2", 200000))
- h.put("small3", strings.Repeat("3", 10))
- h.put("small4", strings.Repeat("4", 10))
- h.tablesPerLevel("")
-
- // Make sure that if we re-open with a small write buffer size that
- // we flush table files in the middle of a large journal file.
- h.o.WriteBuffer = 100000
- h.reopenDB()
- h.getVal("big1", strings.Repeat("1", 200000))
- h.getVal("big2", strings.Repeat("2", 200000))
- h.getVal("small3", strings.Repeat("3", 10))
- h.getVal("small4", strings.Repeat("4", 10))
- v := h.db.s.version()
- if v.tLen(0) <= 1 {
- t.Errorf("tables-0 less than one")
- }
- v.release()
-}
-
-func TestDB_CompactionsGenerateMultipleFiles(t *testing.T) {
- h := newDbHarnessWopt(t, &opt.Options{
- WriteBuffer: 10000000,
- Compression: opt.NoCompression,
- })
- defer h.close()
-
- v := h.db.s.version()
- if v.tLen(0) > 0 {
- t.Errorf("level-0 tables more than 0, got %d", v.tLen(0))
- }
- v.release()
-
- n := 80
-
- // Write 8MB (80 values, each 100K)
- for i := 0; i < n; i++ {
- h.put(numKey(i), strings.Repeat(fmt.Sprintf("v%09d", i), 100000/10))
- }
-
- // Reopening moves updates to level-0
- h.reopenDB()
- h.compactRangeAt(0, "", "")
-
- v = h.db.s.version()
- if v.tLen(0) > 0 {
- t.Errorf("level-0 tables more than 0, got %d", v.tLen(0))
- }
- if v.tLen(1) <= 1 {
- t.Errorf("level-1 tables less than 1, got %d", v.tLen(1))
- }
- v.release()
-
- for i := 0; i < n; i++ {
- h.getVal(numKey(i), strings.Repeat(fmt.Sprintf("v%09d", i), 100000/10))
- }
-}
-
-func TestDB_RepeatedWritesToSameKey(t *testing.T) {
- h := newDbHarnessWopt(t, &opt.Options{WriteBuffer: 100000})
- defer h.close()
-
- maxTables := h.o.GetNumLevel() + h.o.GetWriteL0PauseTrigger()
-
- value := strings.Repeat("v", 2*h.o.GetWriteBuffer())
- for i := 0; i < 5*maxTables; i++ {
- h.put("key", value)
- n := h.totalTables()
- if n > maxTables {
- t.Errorf("total tables exceed %d, got=%d, iter=%d", maxTables, n, i)
- }
- }
-}
-
-func TestDB_RepeatedWritesToSameKeyAfterReopen(t *testing.T) {
- h := newDbHarnessWopt(t, &opt.Options{WriteBuffer: 100000})
- defer h.close()
-
- h.reopenDB()
-
- maxTables := h.o.GetNumLevel() + h.o.GetWriteL0PauseTrigger()
-
- value := strings.Repeat("v", 2*h.o.GetWriteBuffer())
- for i := 0; i < 5*maxTables; i++ {
- h.put("key", value)
- n := h.totalTables()
- if n > maxTables {
- t.Errorf("total tables exceed %d, got=%d, iter=%d", maxTables, n, i)
- }
- }
-}
-
-func TestDB_SparseMerge(t *testing.T) {
- h := newDbHarnessWopt(t, &opt.Options{Compression: opt.NoCompression})
- defer h.close()
-
- h.putMulti(h.o.GetNumLevel(), "A", "Z")
-
- // Suppose there is:
- // small amount of data with prefix A
- // large amount of data with prefix B
- // small amount of data with prefix C
- // and that recent updates have made small changes to all three prefixes.
- // Check that we do not do a compaction that merges all of B in one shot.
- h.put("A", "va")
- value := strings.Repeat("x", 1000)
- for i := 0; i < 100000; i++ {
- h.put(fmt.Sprintf("B%010d", i), value)
- }
- h.put("C", "vc")
- h.compactMem()
- h.compactRangeAt(0, "", "")
- h.waitCompaction()
-
- // Make sparse update
- h.put("A", "va2")
- h.put("B100", "bvalue2")
- h.put("C", "vc2")
- h.compactMem()
-
- h.waitCompaction()
- h.maxNextLevelOverlappingBytes(20 * 1048576)
- h.compactRangeAt(0, "", "")
- h.waitCompaction()
- h.maxNextLevelOverlappingBytes(20 * 1048576)
- h.compactRangeAt(1, "", "")
- h.waitCompaction()
- h.maxNextLevelOverlappingBytes(20 * 1048576)
-}
-
-func TestDB_SizeOf(t *testing.T) {
- h := newDbHarnessWopt(t, &opt.Options{
- Compression: opt.NoCompression,
- WriteBuffer: 10000000,
- })
- defer h.close()
-
- h.sizeAssert("", "xyz", 0, 0)
- h.reopenDB()
- h.sizeAssert("", "xyz", 0, 0)
-
- // Write 8MB (80 values, each 100K)
- n := 80
- s1 := 100000
- s2 := 105000
-
- for i := 0; i < n; i++ {
- h.put(numKey(i), strings.Repeat(fmt.Sprintf("v%09d", i), s1/10))
- }
-
- // 0 because SizeOf() does not account for memtable space
- h.sizeAssert("", numKey(50), 0, 0)
-
- for r := 0; r < 3; r++ {
- h.reopenDB()
-
- for cs := 0; cs < n; cs += 10 {
- for i := 0; i < n; i += 10 {
- h.sizeAssert("", numKey(i), uint64(s1*i), uint64(s2*i))
- h.sizeAssert("", numKey(i)+".suffix", uint64(s1*(i+1)), uint64(s2*(i+1)))
- h.sizeAssert(numKey(i), numKey(i+10), uint64(s1*10), uint64(s2*10))
- }
-
- h.sizeAssert("", numKey(50), uint64(s1*50), uint64(s2*50))
- h.sizeAssert("", numKey(50)+".suffix", uint64(s1*50), uint64(s2*50))
-
- h.compactRangeAt(0, numKey(cs), numKey(cs+9))
- }
-
- v := h.db.s.version()
- if v.tLen(0) != 0 {
- t.Errorf("level-0 tables was not zero, got %d", v.tLen(0))
- }
- if v.tLen(1) == 0 {
- t.Error("level-1 tables was zero")
- }
- v.release()
- }
-}
-
-func TestDB_SizeOf_MixOfSmallAndLarge(t *testing.T) {
- h := newDbHarnessWopt(t, &opt.Options{Compression: opt.NoCompression})
- defer h.close()
-
- sizes := []uint64{
- 10000,
- 10000,
- 100000,
- 10000,
- 100000,
- 10000,
- 300000,
- 10000,
- }
-
- for i, n := range sizes {
- h.put(numKey(i), strings.Repeat(fmt.Sprintf("v%09d", i), int(n)/10))
- }
-
- for r := 0; r < 3; r++ {
- h.reopenDB()
-
- var x uint64
- for i, n := range sizes {
- y := x
- if i > 0 {
- y += 1000
- }
- h.sizeAssert("", numKey(i), x, y)
- x += n
- }
-
- h.sizeAssert(numKey(3), numKey(5), 110000, 111000)
-
- h.compactRangeAt(0, "", "")
- }
-}
-
-func TestDB_Snapshot(t *testing.T) {
- trun(t, func(h *dbHarness) {
- h.put("foo", "v1")
- s1 := h.getSnapshot()
- h.put("foo", "v2")
- s2 := h.getSnapshot()
- h.put("foo", "v3")
- s3 := h.getSnapshot()
- h.put("foo", "v4")
-
- h.getValr(s1, "foo", "v1")
- h.getValr(s2, "foo", "v2")
- h.getValr(s3, "foo", "v3")
- h.getVal("foo", "v4")
-
- s3.Release()
- h.getValr(s1, "foo", "v1")
- h.getValr(s2, "foo", "v2")
- h.getVal("foo", "v4")
-
- s1.Release()
- h.getValr(s2, "foo", "v2")
- h.getVal("foo", "v4")
-
- s2.Release()
- h.getVal("foo", "v4")
- })
-}
-
-func TestDB_SnapshotList(t *testing.T) {
- db := &DB{snapsList: list.New()}
- e0a := db.acquireSnapshot()
- e0b := db.acquireSnapshot()
- db.seq = 1
- e1 := db.acquireSnapshot()
- db.seq = 2
- e2 := db.acquireSnapshot()
-
- if db.minSeq() != 0 {
- t.Fatalf("invalid sequence number, got=%d", db.minSeq())
- }
- db.releaseSnapshot(e0a)
- if db.minSeq() != 0 {
- t.Fatalf("invalid sequence number, got=%d", db.minSeq())
- }
- db.releaseSnapshot(e2)
- if db.minSeq() != 0 {
- t.Fatalf("invalid sequence number, got=%d", db.minSeq())
- }
- db.releaseSnapshot(e0b)
- if db.minSeq() != 1 {
- t.Fatalf("invalid sequence number, got=%d", db.minSeq())
- }
- e2 = db.acquireSnapshot()
- if db.minSeq() != 1 {
- t.Fatalf("invalid sequence number, got=%d", db.minSeq())
- }
- db.releaseSnapshot(e1)
- if db.minSeq() != 2 {
- t.Fatalf("invalid sequence number, got=%d", db.minSeq())
- }
- db.releaseSnapshot(e2)
- if db.minSeq() != 2 {
- t.Fatalf("invalid sequence number, got=%d", db.minSeq())
- }
-}
-
-func TestDB_HiddenValuesAreRemoved(t *testing.T) {
- trun(t, func(h *dbHarness) {
- s := h.db.s
-
- h.put("foo", "v1")
- h.compactMem()
- m := h.o.GetMaxMemCompationLevel()
- v := s.version()
- num := v.tLen(m)
- v.release()
- if num != 1 {
- t.Errorf("invalid level-%d len, want=1 got=%d", m, num)
- }
-
- // Place a table at level last-1 to prevent merging with preceding mutation
- h.put("a", "begin")
- h.put("z", "end")
- h.compactMem()
- v = s.version()
- if v.tLen(m) != 1 {
- t.Errorf("invalid level-%d len, want=1 got=%d", m, v.tLen(m))
- }
- if v.tLen(m-1) != 1 {
- t.Errorf("invalid level-%d len, want=1 got=%d", m-1, v.tLen(m-1))
- }
- v.release()
-
- h.delete("foo")
- h.put("foo", "v2")
- h.allEntriesFor("foo", "[ v2, DEL, v1 ]")
- h.compactMem()
- h.allEntriesFor("foo", "[ v2, DEL, v1 ]")
- h.compactRangeAt(m-2, "", "z")
- // DEL eliminated, but v1 remains because we aren't compacting that level
- // (DEL can be eliminated because v2 hides v1).
- h.allEntriesFor("foo", "[ v2, v1 ]")
- h.compactRangeAt(m-1, "", "")
- // Merging last-1 w/ last, so we are the base level for "foo", so
- // DEL is removed. (as is v1).
- h.allEntriesFor("foo", "[ v2 ]")
- })
-}
-
-func TestDB_DeletionMarkers2(t *testing.T) {
- h := newDbHarness(t)
- defer h.close()
- s := h.db.s
-
- h.put("foo", "v1")
- h.compactMem()
- m := h.o.GetMaxMemCompationLevel()
- v := s.version()
- num := v.tLen(m)
- v.release()
- if num != 1 {
- t.Errorf("invalid level-%d len, want=1 got=%d", m, num)
- }
-
- // Place a table at level last-1 to prevent merging with preceding mutation
- h.put("a", "begin")
- h.put("z", "end")
- h.compactMem()
- v = s.version()
- if v.tLen(m) != 1 {
- t.Errorf("invalid level-%d len, want=1 got=%d", m, v.tLen(m))
- }
- if v.tLen(m-1) != 1 {
- t.Errorf("invalid level-%d len, want=1 got=%d", m-1, v.tLen(m-1))
- }
- v.release()
-
- h.delete("foo")
- h.allEntriesFor("foo", "[ DEL, v1 ]")
- h.compactMem() // Moves to level last-2
- h.allEntriesFor("foo", "[ DEL, v1 ]")
- h.compactRangeAt(m-2, "", "")
- // DEL kept: "last" file overlaps
- h.allEntriesFor("foo", "[ DEL, v1 ]")
- h.compactRangeAt(m-1, "", "")
- // Merging last-1 w/ last, so we are the base level for "foo", so
- // DEL is removed. (as is v1).
- h.allEntriesFor("foo", "[ ]")
-}
-
-func TestDB_CompactionTableOpenError(t *testing.T) {
- h := newDbHarnessWopt(t, &opt.Options{OpenFilesCacheCapacity: -1})
- defer h.close()
-
- im := 10
- jm := 10
- for r := 0; r < 2; r++ {
- for i := 0; i < im; i++ {
- for j := 0; j < jm; j++ {
- h.put(fmt.Sprintf("k%d,%d", i, j), fmt.Sprintf("v%d,%d", i, j))
- }
- h.compactMem()
- }
- }
-
- if n := h.totalTables(); n != im*2 {
- t.Errorf("total tables is %d, want %d", n, im)
- }
-
- h.stor.SetEmuErr(storage.TypeTable, tsOpOpen)
- go h.db.CompactRange(util.Range{})
- if err := h.db.compSendIdle(h.db.tcompCmdC); err != nil {
- t.Log("compaction error: ", err)
- }
- h.closeDB0()
- h.openDB()
- h.stor.SetEmuErr(0, tsOpOpen)
-
- for i := 0; i < im; i++ {
- for j := 0; j < jm; j++ {
- h.getVal(fmt.Sprintf("k%d,%d", i, j), fmt.Sprintf("v%d,%d", i, j))
- }
- }
-}
-
-func TestDB_OverlapInLevel0(t *testing.T) {
- trun(t, func(h *dbHarness) {
- if h.o.GetMaxMemCompationLevel() != 2 {
- t.Fatal("fix test to reflect the config")
- }
-
- // Fill levels 1 and 2 to disable the pushing of new memtables to levels > 0.
- h.put("100", "v100")
- h.put("999", "v999")
- h.compactMem()
- h.delete("100")
- h.delete("999")
- h.compactMem()
- h.tablesPerLevel("0,1,1")
-
- // Make files spanning the following ranges in level-0:
- // files[0] 200 .. 900
- // files[1] 300 .. 500
- // Note that files are sorted by min key.
- h.put("300", "v300")
- h.put("500", "v500")
- h.compactMem()
- h.put("200", "v200")
- h.put("600", "v600")
- h.put("900", "v900")
- h.compactMem()
- h.tablesPerLevel("2,1,1")
-
- // Compact away the placeholder files we created initially
- h.compactRangeAt(1, "", "")
- h.compactRangeAt(2, "", "")
- h.tablesPerLevel("2")
-
- // Do a memtable compaction. Before bug-fix, the compaction would
- // not detect the overlap with level-0 files and would incorrectly place
- // the deletion in a deeper level.
- h.delete("600")
- h.compactMem()
- h.tablesPerLevel("3")
- h.get("600", false)
- })
-}
-
-func TestDB_L0_CompactionBug_Issue44_a(t *testing.T) {
- h := newDbHarness(t)
- defer h.close()
-
- h.reopenDB()
- h.put("b", "v")
- h.reopenDB()
- h.delete("b")
- h.delete("a")
- h.reopenDB()
- h.delete("a")
- h.reopenDB()
- h.put("a", "v")
- h.reopenDB()
- h.reopenDB()
- h.getKeyVal("(a->v)")
- h.waitCompaction()
- h.getKeyVal("(a->v)")
-}
-
-func TestDB_L0_CompactionBug_Issue44_b(t *testing.T) {
- h := newDbHarness(t)
- defer h.close()
-
- h.reopenDB()
- h.put("", "")
- h.reopenDB()
- h.delete("e")
- h.put("", "")
- h.reopenDB()
- h.put("c", "cv")
- h.reopenDB()
- h.put("", "")
- h.reopenDB()
- h.put("", "")
- h.waitCompaction()
- h.reopenDB()
- h.put("d", "dv")
- h.reopenDB()
- h.put("", "")
- h.reopenDB()
- h.delete("d")
- h.delete("b")
- h.reopenDB()
- h.getKeyVal("(->)(c->cv)")
- h.waitCompaction()
- h.getKeyVal("(->)(c->cv)")
-}
-
-func TestDB_SingleEntryMemCompaction(t *testing.T) {
- trun(t, func(h *dbHarness) {
- for i := 0; i < 10; i++ {
- h.put("big", strings.Repeat("v", opt.DefaultWriteBuffer))
- h.compactMem()
- h.put("key", strings.Repeat("v", opt.DefaultBlockSize))
- h.compactMem()
- h.put("k", "v")
- h.compactMem()
- h.put("", "")
- h.compactMem()
- h.put("verybig", strings.Repeat("v", opt.DefaultWriteBuffer*2))
- h.compactMem()
- }
- })
-}
-
-func TestDB_ManifestWriteError(t *testing.T) {
- for i := 0; i < 2; i++ {
- func() {
- h := newDbHarness(t)
- defer h.close()
-
- h.put("foo", "bar")
- h.getVal("foo", "bar")
-
- // Mem compaction (will succeed)
- h.compactMem()
- h.getVal("foo", "bar")
- v := h.db.s.version()
- if n := v.tLen(h.o.GetMaxMemCompationLevel()); n != 1 {
- t.Errorf("invalid total tables, want=1 got=%d", n)
- }
- v.release()
-
- if i == 0 {
- h.stor.SetEmuErr(storage.TypeManifest, tsOpWrite)
- } else {
- h.stor.SetEmuErr(storage.TypeManifest, tsOpSync)
- }
-
- // Merging compaction (will fail)
- h.compactRangeAtErr(h.o.GetMaxMemCompationLevel(), "", "", true)
-
- h.db.Close()
- h.stor.SetEmuErr(0, tsOpWrite)
- h.stor.SetEmuErr(0, tsOpSync)
-
- // Should not lose data
- h.openDB()
- h.getVal("foo", "bar")
- }()
- }
-}
-
-func assertErr(t *testing.T, err error, wanterr bool) {
- if err != nil {
- if wanterr {
- t.Log("AssertErr: got error (expected): ", err)
- } else {
- t.Error("AssertErr: got error: ", err)
- }
- } else if wanterr {
- t.Error("AssertErr: expect error")
- }
-}
-
-func TestDB_ClosedIsClosed(t *testing.T) {
- h := newDbHarness(t)
- db := h.db
-
- var iter, iter2 iterator.Iterator
- var snap *Snapshot
- func() {
- defer h.close()
-
- h.put("k", "v")
- h.getVal("k", "v")
-
- iter = db.NewIterator(nil, h.ro)
- iter.Seek([]byte("k"))
- testKeyVal(t, iter, "k->v")
-
- var err error
- snap, err = db.GetSnapshot()
- if err != nil {
- t.Fatal("GetSnapshot: got error: ", err)
- }
-
- h.getValr(snap, "k", "v")
-
- iter2 = snap.NewIterator(nil, h.ro)
- iter2.Seek([]byte("k"))
- testKeyVal(t, iter2, "k->v")
-
- h.put("foo", "v2")
- h.delete("foo")
-
- // closing DB
- iter.Release()
- iter2.Release()
- }()
-
- assertErr(t, db.Put([]byte("x"), []byte("y"), h.wo), true)
- _, err := db.Get([]byte("k"), h.ro)
- assertErr(t, err, true)
-
- if iter.Valid() {
- t.Errorf("iter.Valid should false")
- }
- assertErr(t, iter.Error(), false)
- testKeyVal(t, iter, "->")
- if iter.Seek([]byte("k")) {
- t.Errorf("iter.Seek should false")
- }
- assertErr(t, iter.Error(), true)
-
- assertErr(t, iter2.Error(), false)
-
- _, err = snap.Get([]byte("k"), h.ro)
- assertErr(t, err, true)
-
- _, err = db.GetSnapshot()
- assertErr(t, err, true)
-
- iter3 := db.NewIterator(nil, h.ro)
- assertErr(t, iter3.Error(), true)
-
- iter3 = snap.NewIterator(nil, h.ro)
- assertErr(t, iter3.Error(), true)
-
- assertErr(t, db.Delete([]byte("k"), h.wo), true)
-
- _, err = db.GetProperty("leveldb.stats")
- assertErr(t, err, true)
-
- _, err = db.SizeOf([]util.Range{{[]byte("a"), []byte("z")}})
- assertErr(t, err, true)
-
- assertErr(t, db.CompactRange(util.Range{}), true)
-
- assertErr(t, db.Close(), true)
-}
-
-type numberComparer struct{}
-
-func (numberComparer) num(x []byte) (n int) {
- fmt.Sscan(string(x[1:len(x)-1]), &n)
- return
-}
-
-func (numberComparer) Name() string {
- return "test.NumberComparer"
-}
-
-func (p numberComparer) Compare(a, b []byte) int {
- return p.num(a) - p.num(b)
-}
-
-func (numberComparer) Separator(dst, a, b []byte) []byte { return nil }
-func (numberComparer) Successor(dst, b []byte) []byte { return nil }
-
-func TestDB_CustomComparer(t *testing.T) {
- h := newDbHarnessWopt(t, &opt.Options{
- Comparer: numberComparer{},
- WriteBuffer: 1000,
- })
- defer h.close()
-
- h.put("[10]", "ten")
- h.put("[0x14]", "twenty")
- for i := 0; i < 2; i++ {
- h.getVal("[10]", "ten")
- h.getVal("[0xa]", "ten")
- h.getVal("[20]", "twenty")
- h.getVal("[0x14]", "twenty")
- h.get("[15]", false)
- h.get("[0xf]", false)
- h.compactMem()
- h.compactRange("[0]", "[9999]")
- }
-
- for n := 0; n < 2; n++ {
- for i := 0; i < 100; i++ {
- v := fmt.Sprintf("[%d]", i*10)
- h.put(v, v)
- }
- h.compactMem()
- h.compactRange("[0]", "[1000000]")
- }
-}
-
-func TestDB_ManualCompaction(t *testing.T) {
- h := newDbHarness(t)
- defer h.close()
-
- if h.o.GetMaxMemCompationLevel() != 2 {
- t.Fatal("fix test to reflect the config")
- }
-
- h.putMulti(3, "p", "q")
- h.tablesPerLevel("1,1,1")
-
- // Compaction range falls before files
- h.compactRange("", "c")
- h.tablesPerLevel("1,1,1")
-
- // Compaction range falls after files
- h.compactRange("r", "z")
- h.tablesPerLevel("1,1,1")
-
- // Compaction range overlaps files
- h.compactRange("p1", "p9")
- h.tablesPerLevel("0,0,1")
-
- // Populate a different range
- h.putMulti(3, "c", "e")
- h.tablesPerLevel("1,1,2")
-
- // Compact just the new range
- h.compactRange("b", "f")
- h.tablesPerLevel("0,0,2")
-
- // Compact all
- h.putMulti(1, "a", "z")
- h.tablesPerLevel("0,1,2")
- h.compactRange("", "")
- h.tablesPerLevel("0,0,1")
-}
-
-func TestDB_BloomFilter(t *testing.T) {
- h := newDbHarnessWopt(t, &opt.Options{
- DisableBlockCache: true,
- Filter: filter.NewBloomFilter(10),
- })
- defer h.close()
-
- key := func(i int) string {
- return fmt.Sprintf("key%06d", i)
- }
-
- const n = 10000
-
- // Populate multiple layers
- for i := 0; i < n; i++ {
- h.put(key(i), key(i))
- }
- h.compactMem()
- h.compactRange("a", "z")
- for i := 0; i < n; i += 100 {
- h.put(key(i), key(i))
- }
- h.compactMem()
-
- // Prevent auto compactions triggered by seeks
- h.stor.DelaySync(storage.TypeTable)
-
- // Lookup present keys. Should rarely read from small sstable.
- h.stor.SetReadCounter(storage.TypeTable)
- for i := 0; i < n; i++ {
- h.getVal(key(i), key(i))
- }
- cnt := int(h.stor.ReadCounter())
- t.Logf("lookup of %d present keys yield %d sstable I/O reads", n, cnt)
-
- if min, max := n, n+2*n/100; cnt < min || cnt > max {
- t.Errorf("num of sstable I/O reads of present keys not in range of %d - %d, got %d", min, max, cnt)
- }
-
- // Lookup missing keys. Should rarely read from either sstable.
- h.stor.ResetReadCounter()
- for i := 0; i < n; i++ {
- h.get(key(i)+".missing", false)
- }
- cnt = int(h.stor.ReadCounter())
- t.Logf("lookup of %d missing keys yield %d sstable I/O reads", n, cnt)
- if max := 3 * n / 100; cnt > max {
- t.Errorf("num of sstable I/O reads of missing keys was more than %d, got %d", max, cnt)
- }
-
- h.stor.ReleaseSync(storage.TypeTable)
-}
-
-func TestDB_Concurrent(t *testing.T) {
- const n, secs, maxkey = 4, 2, 1000
-
- runtime.GOMAXPROCS(n)
- trun(t, func(h *dbHarness) {
- var closeWg sync.WaitGroup
- var stop uint32
- var cnt [n]uint32
-
- for i := 0; i < n; i++ {
- closeWg.Add(1)
- go func(i int) {
- var put, get, found uint
- defer func() {
- t.Logf("goroutine %d stopped after %d ops, put=%d get=%d found=%d missing=%d",
- i, cnt[i], put, get, found, get-found)
- closeWg.Done()
- }()
-
- rnd := rand.New(rand.NewSource(int64(1000 + i)))
- for atomic.LoadUint32(&stop) == 0 {
- x := cnt[i]
-
- k := rnd.Intn(maxkey)
- kstr := fmt.Sprintf("%016d", k)
-
- if (rnd.Int() % 2) > 0 {
- put++
- h.put(kstr, fmt.Sprintf("%d.%d.%-1000d", k, i, x))
- } else {
- get++
- v, err := h.db.Get([]byte(kstr), h.ro)
- if err == nil {
- found++
- rk, ri, rx := 0, -1, uint32(0)
- fmt.Sscanf(string(v), "%d.%d.%d", &rk, &ri, &rx)
- if rk != k {
- t.Errorf("invalid key want=%d got=%d", k, rk)
- }
- if ri < 0 || ri >= n {
- t.Error("invalid goroutine number: ", ri)
- } else {
- tx := atomic.LoadUint32(&(cnt[ri]))
- if rx > tx {
- t.Errorf("invalid seq number, %d > %d ", rx, tx)
- }
- }
- } else if err != ErrNotFound {
- t.Error("Get: got error: ", err)
- return
- }
- }
- atomic.AddUint32(&cnt[i], 1)
- }
- }(i)
- }
-
- time.Sleep(secs * time.Second)
- atomic.StoreUint32(&stop, 1)
- closeWg.Wait()
- })
-
- runtime.GOMAXPROCS(1)
-}
-
-func TestDB_Concurrent2(t *testing.T) {
- const n, n2 = 4, 4000
-
- runtime.GOMAXPROCS(n*2 + 2)
- truno(t, &opt.Options{WriteBuffer: 30}, func(h *dbHarness) {
- var closeWg sync.WaitGroup
- var stop uint32
-
- for i := 0; i < n; i++ {
- closeWg.Add(1)
- go func(i int) {
- for k := 0; atomic.LoadUint32(&stop) == 0; k++ {
- h.put(fmt.Sprintf("k%d", k), fmt.Sprintf("%d.%d.", k, i)+strings.Repeat("x", 10))
- }
- closeWg.Done()
- }(i)
- }
-
- for i := 0; i < n; i++ {
- closeWg.Add(1)
- go func(i int) {
- for k := 1000000; k < 0 || atomic.LoadUint32(&stop) == 0; k-- {
- h.put(fmt.Sprintf("k%d", k), fmt.Sprintf("%d.%d.", k, i)+strings.Repeat("x", 10))
- }
- closeWg.Done()
- }(i)
- }
-
- cmp := comparer.DefaultComparer
- for i := 0; i < n2; i++ {
- closeWg.Add(1)
- go func(i int) {
- it := h.db.NewIterator(nil, nil)
- var pk []byte
- for it.Next() {
- kk := it.Key()
- if cmp.Compare(kk, pk) <= 0 {
- t.Errorf("iter %d: %q is successor of %q", i, pk, kk)
- }
- pk = append(pk[:0], kk...)
- var k, vk, vi int
- if n, err := fmt.Sscanf(string(it.Key()), "k%d", &k); err != nil {
- t.Errorf("iter %d: Scanf error on key %q: %v", i, it.Key(), err)
- } else if n < 1 {
- t.Errorf("iter %d: Cannot parse key %q", i, it.Key())
- }
- if n, err := fmt.Sscanf(string(it.Value()), "%d.%d", &vk, &vi); err != nil {
- t.Errorf("iter %d: Scanf error on value %q: %v", i, it.Value(), err)
- } else if n < 2 {
- t.Errorf("iter %d: Cannot parse value %q", i, it.Value())
- }
-
- if vk != k {
- t.Errorf("iter %d: invalid value i=%d, want=%d got=%d", i, vi, k, vk)
- }
- }
- if err := it.Error(); err != nil {
- t.Errorf("iter %d: Got error: %v", i, err)
- }
- it.Release()
- closeWg.Done()
- }(i)
- }
-
- atomic.StoreUint32(&stop, 1)
- closeWg.Wait()
- })
-
- runtime.GOMAXPROCS(1)
-}
-
-func TestDB_CreateReopenDbOnFile(t *testing.T) {
- dbpath := filepath.Join(os.TempDir(), fmt.Sprintf("goleveldbtestCreateReopenDbOnFile-%d", os.Getuid()))
- if err := os.RemoveAll(dbpath); err != nil {
- t.Fatal("cannot remove old db: ", err)
- }
- defer os.RemoveAll(dbpath)
-
- for i := 0; i < 3; i++ {
- stor, err := storage.OpenFile(dbpath)
- if err != nil {
- t.Fatalf("(%d) cannot open storage: %s", i, err)
- }
- db, err := Open(stor, nil)
- if err != nil {
- t.Fatalf("(%d) cannot open db: %s", i, err)
- }
- if err := db.Put([]byte("foo"), []byte("bar"), nil); err != nil {
- t.Fatalf("(%d) cannot write to db: %s", i, err)
- }
- if err := db.Close(); err != nil {
- t.Fatalf("(%d) cannot close db: %s", i, err)
- }
- if err := stor.Close(); err != nil {
- t.Fatalf("(%d) cannot close storage: %s", i, err)
- }
- }
-}
-
-func TestDB_CreateReopenDbOnFile2(t *testing.T) {
- dbpath := filepath.Join(os.TempDir(), fmt.Sprintf("goleveldbtestCreateReopenDbOnFile2-%d", os.Getuid()))
- if err := os.RemoveAll(dbpath); err != nil {
- t.Fatal("cannot remove old db: ", err)
- }
- defer os.RemoveAll(dbpath)
-
- for i := 0; i < 3; i++ {
- db, err := OpenFile(dbpath, nil)
- if err != nil {
- t.Fatalf("(%d) cannot open db: %s", i, err)
- }
- if err := db.Put([]byte("foo"), []byte("bar"), nil); err != nil {
- t.Fatalf("(%d) cannot write to db: %s", i, err)
- }
- if err := db.Close(); err != nil {
- t.Fatalf("(%d) cannot close db: %s", i, err)
- }
- }
-}
-
-func TestDB_DeletionMarkersOnMemdb(t *testing.T) {
- h := newDbHarness(t)
- defer h.close()
-
- h.put("foo", "v1")
- h.compactMem()
- h.delete("foo")
- h.get("foo", false)
- h.getKeyVal("")
-}
-
-func TestDB_LeveldbIssue178(t *testing.T) {
- nKeys := (opt.DefaultCompactionTableSize / 30) * 5
- key1 := func(i int) string {
- return fmt.Sprintf("my_key_%d", i)
- }
- key2 := func(i int) string {
- return fmt.Sprintf("my_key_%d_xxx", i)
- }
-
- // Disable compression since it affects the creation of layers and the
- // code below is trying to test against a very specific scenario.
- h := newDbHarnessWopt(t, &opt.Options{Compression: opt.NoCompression})
- defer h.close()
-
- // Create first key range.
- batch := new(Batch)
- for i := 0; i < nKeys; i++ {
- batch.Put([]byte(key1(i)), []byte("value for range 1 key"))
- }
- h.write(batch)
-
- // Create second key range.
- batch.Reset()
- for i := 0; i < nKeys; i++ {
- batch.Put([]byte(key2(i)), []byte("value for range 2 key"))
- }
- h.write(batch)
-
- // Delete second key range.
- batch.Reset()
- for i := 0; i < nKeys; i++ {
- batch.Delete([]byte(key2(i)))
- }
- h.write(batch)
- h.waitMemCompaction()
-
- // Run manual compaction.
- h.compactRange(key1(0), key1(nKeys-1))
-
- // Checking the keys.
- h.assertNumKeys(nKeys)
-}
-
-func TestDB_LeveldbIssue200(t *testing.T) {
- h := newDbHarness(t)
- defer h.close()
-
- h.put("1", "b")
- h.put("2", "c")
- h.put("3", "d")
- h.put("4", "e")
- h.put("5", "f")
-
- iter := h.db.NewIterator(nil, h.ro)
-
- // Add an element that should not be reflected in the iterator.
- h.put("25", "cd")
-
- iter.Seek([]byte("5"))
- assertBytes(t, []byte("5"), iter.Key())
- iter.Prev()
- assertBytes(t, []byte("4"), iter.Key())
- iter.Prev()
- assertBytes(t, []byte("3"), iter.Key())
- iter.Next()
- assertBytes(t, []byte("4"), iter.Key())
- iter.Next()
- assertBytes(t, []byte("5"), iter.Key())
-}
-
-func TestDB_GoleveldbIssue74(t *testing.T) {
- h := newDbHarnessWopt(t, &opt.Options{
- WriteBuffer: 1 * opt.MiB,
- })
- defer h.close()
-
- const n, dur = 10000, 5 * time.Second
-
- runtime.GOMAXPROCS(runtime.NumCPU())
-
- until := time.Now().Add(dur)
- wg := new(sync.WaitGroup)
- wg.Add(2)
- var done uint32
- go func() {
- var i int
- defer func() {
- t.Logf("WRITER DONE #%d", i)
- atomic.StoreUint32(&done, 1)
- wg.Done()
- }()
-
- b := new(Batch)
- for ; time.Now().Before(until) && atomic.LoadUint32(&done) == 0; i++ {
- iv := fmt.Sprintf("VAL%010d", i)
- for k := 0; k < n; k++ {
- key := fmt.Sprintf("KEY%06d", k)
- b.Put([]byte(key), []byte(key+iv))
- b.Put([]byte(fmt.Sprintf("PTR%06d", k)), []byte(key))
- }
- h.write(b)
-
- b.Reset()
- snap := h.getSnapshot()
- iter := snap.NewIterator(util.BytesPrefix([]byte("PTR")), nil)
- var k int
- for ; iter.Next(); k++ {
- ptrKey := iter.Key()
- key := iter.Value()
-
- if _, err := snap.Get(ptrKey, nil); err != nil {
- t.Fatalf("WRITER #%d snapshot.Get %q: %v", i, ptrKey, err)
- }
- if value, err := snap.Get(key, nil); err != nil {
- t.Fatalf("WRITER #%d snapshot.Get %q: %v", i, key, err)
- } else if string(value) != string(key)+iv {
- t.Fatalf("WRITER #%d snapshot.Get %q got invalid value, want %q got %q", i, key, string(key)+iv, value)
- }
-
- b.Delete(key)
- b.Delete(ptrKey)
- }
- h.write(b)
- iter.Release()
- snap.Release()
- if k != n {
- t.Fatalf("#%d %d != %d", i, k, n)
- }
- }
- }()
- go func() {
- var i int
- defer func() {
- t.Logf("READER DONE #%d", i)
- atomic.StoreUint32(&done, 1)
- wg.Done()
- }()
- for ; time.Now().Before(until) && atomic.LoadUint32(&done) == 0; i++ {
- snap := h.getSnapshot()
- iter := snap.NewIterator(util.BytesPrefix([]byte("PTR")), nil)
- var prevValue string
- var k int
- for ; iter.Next(); k++ {
- ptrKey := iter.Key()
- key := iter.Value()
-
- if _, err := snap.Get(ptrKey, nil); err != nil {
- t.Fatalf("READER #%d snapshot.Get %q: %v", i, ptrKey, err)
- }
-
- if value, err := snap.Get(key, nil); err != nil {
- t.Fatalf("READER #%d snapshot.Get %q: %v", i, key, err)
- } else if prevValue != "" && string(value) != string(key)+prevValue {
- t.Fatalf("READER #%d snapshot.Get %q got invalid value, want %q got %q", i, key, string(key)+prevValue, value)
- } else {
- prevValue = string(value[len(key):])
- }
- }
- iter.Release()
- snap.Release()
- if k > 0 && k != n {
- t.Fatalf("#%d %d != %d", i, k, n)
- }
- }
- }()
- wg.Wait()
-}
-
-func TestDB_GetProperties(t *testing.T) {
- h := newDbHarness(t)
- defer h.close()
-
- _, err := h.db.GetProperty("leveldb.num-files-at-level")
- if err == nil {
- t.Error("GetProperty() failed to detect missing level")
- }
-
- _, err = h.db.GetProperty("leveldb.num-files-at-level0")
- if err != nil {
- t.Error("got unexpected error", err)
- }
-
- _, err = h.db.GetProperty("leveldb.num-files-at-level0x")
- if err == nil {
- t.Error("GetProperty() failed to detect invalid level")
- }
-}
-
-func TestDB_GoleveldbIssue72and83(t *testing.T) {
- h := newDbHarnessWopt(t, &opt.Options{
- WriteBuffer: 1 * opt.MiB,
- OpenFilesCacheCapacity: 3,
- })
- defer h.close()
-
- const n, wn, dur = 10000, 100, 30 * time.Second
-
- runtime.GOMAXPROCS(runtime.NumCPU())
-
- randomData := func(prefix byte, i int) []byte {
- data := make([]byte, 1+4+32+64+32)
- _, err := crand.Reader.Read(data[1 : len(data)-8])
- if err != nil {
- panic(err)
- }
- data[0] = prefix
- binary.LittleEndian.PutUint32(data[len(data)-8:], uint32(i))
- binary.LittleEndian.PutUint32(data[len(data)-4:], util.NewCRC(data[:len(data)-4]).Value())
- return data
- }
-
- keys := make([][]byte, n)
- for i := range keys {
- keys[i] = randomData(1, 0)
- }
-
- until := time.Now().Add(dur)
- wg := new(sync.WaitGroup)
- wg.Add(3)
- var done uint32
- go func() {
- i := 0
- defer func() {
- t.Logf("WRITER DONE #%d", i)
- wg.Done()
- }()
-
- b := new(Batch)
- for ; i < wn && atomic.LoadUint32(&done) == 0; i++ {
- b.Reset()
- for _, k1 := range keys {
- k2 := randomData(2, i)
- b.Put(k2, randomData(42, i))
- b.Put(k1, k2)
- }
- if err := h.db.Write(b, h.wo); err != nil {
- atomic.StoreUint32(&done, 1)
- t.Fatalf("WRITER #%d db.Write: %v", i, err)
- }
- }
- }()
- go func() {
- var i int
- defer func() {
- t.Logf("READER0 DONE #%d", i)
- atomic.StoreUint32(&done, 1)
- wg.Done()
- }()
- for ; time.Now().Before(until) && atomic.LoadUint32(&done) == 0; i++ {
- snap := h.getSnapshot()
- seq := snap.elem.seq
- if seq == 0 {
- snap.Release()
- continue
- }
- iter := snap.NewIterator(util.BytesPrefix([]byte{1}), nil)
- writei := int(seq/(n*2) - 1)
- var k int
- for ; iter.Next(); k++ {
- k1 := iter.Key()
- k2 := iter.Value()
- k1checksum0 := binary.LittleEndian.Uint32(k1[len(k1)-4:])
- k1checksum1 := util.NewCRC(k1[:len(k1)-4]).Value()
- if k1checksum0 != k1checksum1 {
- t.Fatalf("READER0 #%d.%d W#%d invalid K1 checksum: %#x != %#x", i, k, k1checksum0, k1checksum0)
- }
- k2checksum0 := binary.LittleEndian.Uint32(k2[len(k2)-4:])
- k2checksum1 := util.NewCRC(k2[:len(k2)-4]).Value()
- if k2checksum0 != k2checksum1 {
- t.Fatalf("READER0 #%d.%d W#%d invalid K2 checksum: %#x != %#x", i, k, k2checksum0, k2checksum1)
- }
- kwritei := int(binary.LittleEndian.Uint32(k2[len(k2)-8:]))
- if writei != kwritei {
- t.Fatalf("READER0 #%d.%d W#%d invalid write iteration num: %d", i, k, writei, kwritei)
- }
- if _, err := snap.Get(k2, nil); err != nil {
- t.Fatalf("READER0 #%d.%d W#%d snap.Get: %v\nk1: %x\n -> k2: %x", i, k, writei, err, k1, k2)
- }
- }
- if err := iter.Error(); err != nil {
- t.Fatalf("READER0 #%d.%d W#%d snap.Iterator: %v", i, k, writei, err)
- }
- iter.Release()
- snap.Release()
- if k > 0 && k != n {
- t.Fatalf("READER0 #%d W#%d short read, got=%d want=%d", i, writei, k, n)
- }
- }
- }()
- go func() {
- var i int
- defer func() {
- t.Logf("READER1 DONE #%d", i)
- atomic.StoreUint32(&done, 1)
- wg.Done()
- }()
- for ; time.Now().Before(until) && atomic.LoadUint32(&done) == 0; i++ {
- iter := h.db.NewIterator(nil, nil)
- seq := iter.(*dbIter).seq
- if seq == 0 {
- iter.Release()
- continue
- }
- writei := int(seq/(n*2) - 1)
- var k int
- for ok := iter.Last(); ok; ok = iter.Prev() {
- k++
- }
- if err := iter.Error(); err != nil {
- t.Fatalf("READER1 #%d.%d W#%d db.Iterator: %v", i, k, writei, err)
- }
- iter.Release()
- if m := (writei+1)*n + n; k != m {
- t.Fatalf("READER1 #%d W#%d short read, got=%d want=%d", i, writei, k, m)
- }
- }
- }()
-
- wg.Wait()
-}
-
-func TestDB_TransientError(t *testing.T) {
- h := newDbHarnessWopt(t, &opt.Options{
- WriteBuffer: 128 * opt.KiB,
- OpenFilesCacheCapacity: 3,
- DisableCompactionBackoff: true,
- })
- defer h.close()
-
- const (
- nSnap = 20
- nKey = 10000
- )
-
- var (
- snaps [nSnap]*Snapshot
- b = &Batch{}
- )
- for i := range snaps {
- vtail := fmt.Sprintf("VAL%030d", i)
- b.Reset()
- for k := 0; k < nKey; k++ {
- key := fmt.Sprintf("KEY%8d", k)
- b.Put([]byte(key), []byte(key+vtail))
- }
- h.stor.SetEmuRandErr(storage.TypeTable, tsOpOpen, tsOpRead, tsOpReadAt)
- if err := h.db.Write(b, nil); err != nil {
- t.Logf("WRITE #%d error: %v", i, err)
- h.stor.SetEmuRandErr(0, tsOpOpen, tsOpRead, tsOpReadAt, tsOpWrite)
- for {
- if err := h.db.Write(b, nil); err == nil {
- break
- } else if errors.IsCorrupted(err) {
- t.Fatalf("WRITE #%d corrupted: %v", i, err)
- }
- }
- }
-
- snaps[i] = h.db.newSnapshot()
- b.Reset()
- for k := 0; k < nKey; k++ {
- key := fmt.Sprintf("KEY%8d", k)
- b.Delete([]byte(key))
- }
- h.stor.SetEmuRandErr(storage.TypeTable, tsOpOpen, tsOpRead, tsOpReadAt)
- if err := h.db.Write(b, nil); err != nil {
- t.Logf("WRITE #%d error: %v", i, err)
- h.stor.SetEmuRandErr(0, tsOpOpen, tsOpRead, tsOpReadAt)
- for {
- if err := h.db.Write(b, nil); err == nil {
- break
- } else if errors.IsCorrupted(err) {
- t.Fatalf("WRITE #%d corrupted: %v", i, err)
- }
- }
- }
- }
- h.stor.SetEmuRandErr(0, tsOpOpen, tsOpRead, tsOpReadAt)
-
- runtime.GOMAXPROCS(runtime.NumCPU())
-
- rnd := rand.New(rand.NewSource(0xecafdaed))
- wg := &sync.WaitGroup{}
- for i, snap := range snaps {
- wg.Add(2)
-
- go func(i int, snap *Snapshot, sk []int) {
- defer wg.Done()
-
- vtail := fmt.Sprintf("VAL%030d", i)
- for _, k := range sk {
- key := fmt.Sprintf("KEY%8d", k)
- xvalue, err := snap.Get([]byte(key), nil)
- if err != nil {
- t.Fatalf("READER_GET #%d SEQ=%d K%d error: %v", i, snap.elem.seq, k, err)
- }
- value := key + vtail
- if !bytes.Equal([]byte(value), xvalue) {
- t.Fatalf("READER_GET #%d SEQ=%d K%d invalid value: want %q, got %q", i, snap.elem.seq, k, value, xvalue)
- }
- }
- }(i, snap, rnd.Perm(nKey))
-
- go func(i int, snap *Snapshot) {
- defer wg.Done()
-
- vtail := fmt.Sprintf("VAL%030d", i)
- iter := snap.NewIterator(nil, nil)
- defer iter.Release()
- for k := 0; k < nKey; k++ {
- if !iter.Next() {
- if err := iter.Error(); err != nil {
- t.Fatalf("READER_ITER #%d K%d error: %v", i, k, err)
- } else {
- t.Fatalf("READER_ITER #%d K%d eoi", i, k)
- }
- }
- key := fmt.Sprintf("KEY%8d", k)
- xkey := iter.Key()
- if !bytes.Equal([]byte(key), xkey) {
- t.Fatalf("READER_ITER #%d K%d invalid key: want %q, got %q", i, k, key, xkey)
- }
- value := key + vtail
- xvalue := iter.Value()
- if !bytes.Equal([]byte(value), xvalue) {
- t.Fatalf("READER_ITER #%d K%d invalid value: want %q, got %q", i, k, value, xvalue)
- }
- }
- }(i, snap)
- }
-
- wg.Wait()
-}
-
-func TestDB_UkeyShouldntHopAcrossTable(t *testing.T) {
- h := newDbHarnessWopt(t, &opt.Options{
- WriteBuffer: 112 * opt.KiB,
- CompactionTableSize: 90 * opt.KiB,
- CompactionExpandLimitFactor: 1,
- })
- defer h.close()
-
- const (
- nSnap = 190
- nKey = 140
- )
-
- var (
- snaps [nSnap]*Snapshot
- b = &Batch{}
- )
- for i := range snaps {
- vtail := fmt.Sprintf("VAL%030d", i)
- b.Reset()
- for k := 0; k < nKey; k++ {
- key := fmt.Sprintf("KEY%08d", k)
- b.Put([]byte(key), []byte(key+vtail))
- }
- if err := h.db.Write(b, nil); err != nil {
- t.Fatalf("WRITE #%d error: %v", i, err)
- }
-
- snaps[i] = h.db.newSnapshot()
- b.Reset()
- for k := 0; k < nKey; k++ {
- key := fmt.Sprintf("KEY%08d", k)
- b.Delete([]byte(key))
- }
- if err := h.db.Write(b, nil); err != nil {
- t.Fatalf("WRITE #%d error: %v", i, err)
- }
- }
-
- h.compactMem()
-
- h.waitCompaction()
- for level, tables := range h.db.s.stVersion.tables {
- for _, table := range tables {
- t.Logf("L%d@%d %q:%q", level, table.file.Num(), table.imin, table.imax)
- }
- }
-
- h.compactRangeAt(0, "", "")
- h.waitCompaction()
- for level, tables := range h.db.s.stVersion.tables {
- for _, table := range tables {
- t.Logf("L%d@%d %q:%q", level, table.file.Num(), table.imin, table.imax)
- }
- }
- h.compactRangeAt(1, "", "")
- h.waitCompaction()
- for level, tables := range h.db.s.stVersion.tables {
- for _, table := range tables {
- t.Logf("L%d@%d %q:%q", level, table.file.Num(), table.imin, table.imax)
- }
- }
- runtime.GOMAXPROCS(runtime.NumCPU())
-
- wg := &sync.WaitGroup{}
- for i, snap := range snaps {
- wg.Add(1)
-
- go func(i int, snap *Snapshot) {
- defer wg.Done()
-
- vtail := fmt.Sprintf("VAL%030d", i)
- for k := 0; k < nKey; k++ {
- key := fmt.Sprintf("KEY%08d", k)
- xvalue, err := snap.Get([]byte(key), nil)
- if err != nil {
- t.Fatalf("READER_GET #%d SEQ=%d K%d error: %v", i, snap.elem.seq, k, err)
- }
- value := key + vtail
- if !bytes.Equal([]byte(value), xvalue) {
- t.Fatalf("READER_GET #%d SEQ=%d K%d invalid value: want %q, got %q", i, snap.elem.seq, k, value, xvalue)
- }
- }
- }(i, snap)
- }
-
- wg.Wait()
-}
-
-func TestDB_TableCompactionBuilder(t *testing.T) {
- stor := newTestStorage(t)
- defer stor.Close()
-
- const nSeq = 99
-
- o := &opt.Options{
- WriteBuffer: 112 * opt.KiB,
- CompactionTableSize: 43 * opt.KiB,
- CompactionExpandLimitFactor: 1,
- CompactionGPOverlapsFactor: 1,
- DisableBlockCache: true,
- }
- s, err := newSession(stor, o)
- if err != nil {
- t.Fatal(err)
- }
- if err := s.create(); err != nil {
- t.Fatal(err)
- }
- defer s.close()
- var (
- seq uint64
- targetSize = 5 * o.CompactionTableSize
- value = bytes.Repeat([]byte{'0'}, 100)
- )
- for i := 0; i < 2; i++ {
- tw, err := s.tops.create()
- if err != nil {
- t.Fatal(err)
- }
- for k := 0; tw.tw.BytesLen() < targetSize; k++ {
- key := []byte(fmt.Sprintf("%09d", k))
- seq += nSeq - 1
- for x := uint64(0); x < nSeq; x++ {
- if err := tw.append(newIkey(key, seq-x, ktVal), value); err != nil {
- t.Fatal(err)
- }
- }
- }
- tf, err := tw.finish()
- if err != nil {
- t.Fatal(err)
- }
- rec := &sessionRecord{numLevel: s.o.GetNumLevel()}
- rec.addTableFile(i, tf)
- if err := s.commit(rec); err != nil {
- t.Fatal(err)
- }
- }
-
- // Build grandparent.
- v := s.version()
- c := newCompaction(s, v, 1, append(tFiles{}, v.tables[1]...))
- rec := &sessionRecord{numLevel: s.o.GetNumLevel()}
- b := &tableCompactionBuilder{
- s: s,
- c: c,
- rec: rec,
- stat1: new(cStatsStaging),
- minSeq: 0,
- strict: true,
- tableSize: o.CompactionTableSize/3 + 961,
- }
- if err := b.run(new(compactionTransactCounter)); err != nil {
- t.Fatal(err)
- }
- for _, t := range c.tables[0] {
- rec.delTable(c.level, t.file.Num())
- }
- if err := s.commit(rec); err != nil {
- t.Fatal(err)
- }
- c.release()
-
- // Build level-1.
- v = s.version()
- c = newCompaction(s, v, 0, append(tFiles{}, v.tables[0]...))
- rec = &sessionRecord{numLevel: s.o.GetNumLevel()}
- b = &tableCompactionBuilder{
- s: s,
- c: c,
- rec: rec,
- stat1: new(cStatsStaging),
- minSeq: 0,
- strict: true,
- tableSize: o.CompactionTableSize,
- }
- if err := b.run(new(compactionTransactCounter)); err != nil {
- t.Fatal(err)
- }
- for _, t := range c.tables[0] {
- rec.delTable(c.level, t.file.Num())
- }
- // Move grandparent to level-3
- for _, t := range v.tables[2] {
- rec.delTable(2, t.file.Num())
- rec.addTableFile(3, t)
- }
- if err := s.commit(rec); err != nil {
- t.Fatal(err)
- }
- c.release()
-
- v = s.version()
- for level, want := range []bool{false, true, false, true, false} {
- got := len(v.tables[level]) > 0
- if want != got {
- t.Fatalf("invalid level-%d tables len: want %v, got %v", level, want, got)
- }
- }
- for i, f := range v.tables[1][:len(v.tables[1])-1] {
- nf := v.tables[1][i+1]
- if bytes.Equal(f.imax.ukey(), nf.imin.ukey()) {
- t.Fatalf("KEY %q hop across table %d .. %d", f.imax.ukey(), f.file.Num(), nf.file.Num())
- }
- }
- v.release()
-
- // Compaction with transient error.
- v = s.version()
- c = newCompaction(s, v, 1, append(tFiles{}, v.tables[1]...))
- rec = &sessionRecord{numLevel: s.o.GetNumLevel()}
- b = &tableCompactionBuilder{
- s: s,
- c: c,
- rec: rec,
- stat1: new(cStatsStaging),
- minSeq: 0,
- strict: true,
- tableSize: o.CompactionTableSize,
- }
- stor.SetEmuErrOnce(storage.TypeTable, tsOpSync)
- stor.SetEmuRandErr(storage.TypeTable, tsOpRead, tsOpReadAt, tsOpWrite)
- stor.SetEmuRandErrProb(0xf0)
- for {
- if err := b.run(new(compactionTransactCounter)); err != nil {
- t.Logf("(expected) b.run: %v", err)
- } else {
- break
- }
- }
- if err := s.commit(rec); err != nil {
- t.Fatal(err)
- }
- c.release()
-
- stor.SetEmuErrOnce(0, tsOpSync)
- stor.SetEmuRandErr(0, tsOpRead, tsOpReadAt, tsOpWrite)
-
- v = s.version()
- if len(v.tables[1]) != len(v.tables[2]) {
- t.Fatalf("invalid tables length, want %d, got %d", len(v.tables[1]), len(v.tables[2]))
- }
- for i, f0 := range v.tables[1] {
- f1 := v.tables[2][i]
- iter0 := s.tops.newIterator(f0, nil, nil)
- iter1 := s.tops.newIterator(f1, nil, nil)
- for j := 0; true; j++ {
- next0 := iter0.Next()
- next1 := iter1.Next()
- if next0 != next1 {
- t.Fatalf("#%d.%d invalid eoi: want %v, got %v", i, j, next0, next1)
- }
- key0 := iter0.Key()
- key1 := iter1.Key()
- if !bytes.Equal(key0, key1) {
- t.Fatalf("#%d.%d invalid key: want %q, got %q", i, j, key0, key1)
- }
- if next0 == false {
- break
- }
- }
- iter0.Release()
- iter1.Release()
- }
- v.release()
-}
-
-func testDB_IterTriggeredCompaction(t *testing.T, limitDiv int) {
- const (
- vSize = 200 * opt.KiB
- tSize = 100 * opt.MiB
- mIter = 100
- n = tSize / vSize
- )
-
- h := newDbHarnessWopt(t, &opt.Options{
- Compression: opt.NoCompression,
- DisableBlockCache: true,
- })
- defer h.close()
-
- key := func(x int) string {
- return fmt.Sprintf("v%06d", x)
- }
-
- // Fill.
- value := strings.Repeat("x", vSize)
- for i := 0; i < n; i++ {
- h.put(key(i), value)
- }
- h.compactMem()
-
- // Delete all.
- for i := 0; i < n; i++ {
- h.delete(key(i))
- }
- h.compactMem()
-
- var (
- limit = n / limitDiv
-
- startKey = key(0)
- limitKey = key(limit)
- maxKey = key(n)
- slice = &util.Range{Limit: []byte(limitKey)}
-
- initialSize0 = h.sizeOf(startKey, limitKey)
- initialSize1 = h.sizeOf(limitKey, maxKey)
- )
-
- t.Logf("inital size %s [rest %s]", shortenb(int(initialSize0)), shortenb(int(initialSize1)))
-
- for r := 0; true; r++ {
- if r >= mIter {
- t.Fatal("taking too long to compact")
- }
-
- // Iterates.
- iter := h.db.NewIterator(slice, h.ro)
- for iter.Next() {
- }
- if err := iter.Error(); err != nil {
- t.Fatalf("Iter err: %v", err)
- }
- iter.Release()
-
- // Wait compaction.
- h.waitCompaction()
-
- // Check size.
- size0 := h.sizeOf(startKey, limitKey)
- size1 := h.sizeOf(limitKey, maxKey)
- t.Logf("#%03d size %s [rest %s]", r, shortenb(int(size0)), shortenb(int(size1)))
- if size0 < initialSize0/10 {
- break
- }
- }
-
- if initialSize1 > 0 {
- h.sizeAssert(limitKey, maxKey, initialSize1/4-opt.MiB, initialSize1+opt.MiB)
- }
-}
-
-func TestDB_IterTriggeredCompaction(t *testing.T) {
- testDB_IterTriggeredCompaction(t, 1)
-}
-
-func TestDB_IterTriggeredCompactionHalf(t *testing.T) {
- testDB_IterTriggeredCompaction(t, 2)
-}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_transaction.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_transaction.go
new file mode 100644
index 000000000..527028756
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_transaction.go
@@ -0,0 +1,289 @@
+// Copyright (c) 2016, Suryandaru Triandana <syndtr@gmail.com>
+// All rights reserved.
+//
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package leveldb
+
+import (
+ "errors"
+ "sync"
+ "time"
+
+ "github.com/syndtr/goleveldb/leveldb/iterator"
+ "github.com/syndtr/goleveldb/leveldb/opt"
+ "github.com/syndtr/goleveldb/leveldb/util"
+)
+
+var errTransactionDone = errors.New("leveldb: transaction already closed")
+
+// Transaction is the transaction handle.
+type Transaction struct {
+ db *DB
+ lk sync.RWMutex
+ seq uint64
+ mem *memDB
+ tables tFiles
+ ikScratch []byte
+ rec sessionRecord
+ stats cStatStaging
+ closed bool
+}
+
+// Get gets the value for the given key. It returns ErrNotFound if the
+// DB does not contains the key.
+//
+// The returned slice is its own copy, it is safe to modify the contents
+// of the returned slice.
+// It is safe to modify the contents of the argument after Get returns.
+func (tr *Transaction) Get(key []byte, ro *opt.ReadOptions) ([]byte, error) {
+ tr.lk.RLock()
+ defer tr.lk.RUnlock()
+ if tr.closed {
+ return nil, errTransactionDone
+ }
+ return tr.db.get(tr.mem.DB, tr.tables, key, tr.seq, ro)
+}
+
+// Has returns true if the DB does contains the given key.
+//
+// It is safe to modify the contents of the argument after Has returns.
+func (tr *Transaction) Has(key []byte, ro *opt.ReadOptions) (bool, error) {
+ tr.lk.RLock()
+ defer tr.lk.RUnlock()
+ if tr.closed {
+ return false, errTransactionDone
+ }
+ return tr.db.has(tr.mem.DB, tr.tables, key, tr.seq, ro)
+}
+
+// NewIterator returns an iterator for the latest snapshot of the transaction.
+// The returned iterator is not goroutine-safe, but it is safe to use multiple
+// iterators concurrently, with each in a dedicated goroutine.
+// It is also safe to use an iterator concurrently while writes to the
+// transaction. The resultant key/value pairs are guaranteed to be consistent.
+//
+// Slice allows slicing the iterator to only contains keys in the given
+// range. A nil Range.Start is treated as a key before all keys in the
+// DB. And a nil Range.Limit is treated as a key after all keys in
+// the DB.
+//
+// The iterator must be released after use, by calling Release method.
+//
+// Also read Iterator documentation of the leveldb/iterator package.
+func (tr *Transaction) NewIterator(slice *util.Range, ro *opt.ReadOptions) iterator.Iterator {
+ tr.lk.RLock()
+ defer tr.lk.RUnlock()
+ if tr.closed {
+ return iterator.NewEmptyIterator(errTransactionDone)
+ }
+ tr.mem.incref()
+ return tr.db.newIterator(tr.mem, tr.tables, tr.seq, slice, ro)
+}
+
+func (tr *Transaction) flush() error {
+ // Flush memdb.
+ if tr.mem.Len() != 0 {
+ tr.stats.startTimer()
+ iter := tr.mem.NewIterator(nil)
+ t, n, err := tr.db.s.tops.createFrom(iter)
+ iter.Release()
+ tr.stats.stopTimer()
+ if err != nil {
+ return err
+ }
+ if tr.mem.getref() == 1 {
+ tr.mem.Reset()
+ } else {
+ tr.mem.decref()
+ tr.mem = tr.db.mpoolGet(0)
+ tr.mem.incref()
+ }
+ tr.tables = append(tr.tables, t)
+ tr.rec.addTableFile(0, t)
+ tr.stats.write += t.size
+ tr.db.logf("transaction@flush created L0@%d N·%d S·%s %q:%q", t.fd.Num, n, shortenb(int(t.size)), t.imin, t.imax)
+ }
+ return nil
+}
+
+func (tr *Transaction) put(kt kType, key, value []byte) error {
+ tr.ikScratch = makeIkey(tr.ikScratch, key, tr.seq+1, kt)
+ if tr.mem.Free() < len(tr.ikScratch)+len(value) {
+ if err := tr.flush(); err != nil {
+ return err
+ }
+ }
+ if err := tr.mem.Put(tr.ikScratch, value); err != nil {
+ return err
+ }
+ tr.seq++
+ return nil
+}
+
+// Put sets the value for the given key. It overwrites any previous value
+// for that key; a DB is not a multi-map.
+// Please note that the transaction is not compacted until committed, so if you
+// writes 10 same keys, then those 10 same keys are in the transaction.
+//
+// It is safe to modify the contents of the arguments after Put returns.
+func (tr *Transaction) Put(key, value []byte, wo *opt.WriteOptions) error {
+ tr.lk.Lock()
+ defer tr.lk.Unlock()
+ if tr.closed {
+ return errTransactionDone
+ }
+ return tr.put(ktVal, key, value)
+}
+
+// Delete deletes the value for the given key.
+// Please note that the transaction is not compacted until committed, so if you
+// writes 10 same keys, then those 10 same keys are in the transaction.
+//
+// It is safe to modify the contents of the arguments after Delete returns.
+func (tr *Transaction) Delete(key []byte, wo *opt.WriteOptions) error {
+ tr.lk.Lock()
+ defer tr.lk.Unlock()
+ if tr.closed {
+ return errTransactionDone
+ }
+ return tr.put(ktDel, key, nil)
+}
+
+// Write apply the given batch to the transaction. The batch will be applied
+// sequentially.
+// Please note that the transaction is not compacted until committed, so if you
+// writes 10 same keys, then those 10 same keys are in the transaction.
+//
+// It is safe to modify the contents of the arguments after Write returns.
+func (tr *Transaction) Write(b *Batch, wo *opt.WriteOptions) error {
+ if b == nil || b.Len() == 0 {
+ return nil
+ }
+
+ tr.lk.Lock()
+ defer tr.lk.Unlock()
+ if tr.closed {
+ return errTransactionDone
+ }
+ return b.decodeRec(func(i int, kt kType, key, value []byte) error {
+ return tr.put(kt, key, value)
+ })
+}
+
+func (tr *Transaction) setDone() {
+ tr.closed = true
+ tr.db.tr = nil
+ tr.mem.decref()
+ <-tr.db.writeLockC
+}
+
+// Commit commits the transaction.
+//
+// Other methods should not be called after transaction has been committed.
+func (tr *Transaction) Commit() error {
+ if err := tr.db.ok(); err != nil {
+ return err
+ }
+
+ tr.lk.Lock()
+ defer tr.lk.Unlock()
+ if tr.closed {
+ return errTransactionDone
+ }
+ defer tr.setDone()
+ if err := tr.flush(); err != nil {
+ tr.discard()
+ return err
+ }
+ if len(tr.tables) != 0 {
+ // Committing transaction.
+ tr.rec.setSeqNum(tr.seq)
+ tr.db.compCommitLk.Lock()
+ defer tr.db.compCommitLk.Unlock()
+ for retry := 0; retry < 3; retry++ {
+ if err := tr.db.s.commit(&tr.rec); err != nil {
+ tr.db.logf("transaction@commit error R·%d %q", retry, err)
+ select {
+ case <-time.After(time.Second):
+ case _, _ = <-tr.db.closeC:
+ tr.db.logf("transaction@commit exiting")
+ return err
+ }
+ } else {
+ // Success. Set db.seq.
+ tr.db.setSeq(tr.seq)
+ break
+ }
+ }
+ // Trigger table auto-compaction.
+ tr.db.compTrigger(tr.db.tcompCmdC)
+ }
+ return nil
+}
+
+func (tr *Transaction) discard() {
+ // Discard transaction.
+ for _, t := range tr.tables {
+ tr.db.logf("transaction@discard @%d", t.fd.Num)
+ if err1 := tr.db.s.stor.Remove(t.fd); err1 == nil {
+ tr.db.s.reuseFileNum(t.fd.Num)
+ }
+ }
+}
+
+// Discard discards the transaction.
+//
+// Other methods should not be called after transaction has been discarded.
+func (tr *Transaction) Discard() {
+ tr.lk.Lock()
+ if !tr.closed {
+ tr.discard()
+ tr.setDone()
+ }
+ tr.lk.Unlock()
+}
+
+// OpenTransaction opens an atomic DB transaction. Only one transaction can be
+// opened at a time. Write will be blocked until the transaction is committed or
+// discarded.
+// The returned transaction handle is goroutine-safe.
+//
+// The transaction must be closed once done, either by committing or discarding
+// the transaction.
+// Closing the DB will discard open transaction.
+func (db *DB) OpenTransaction() (*Transaction, error) {
+ if err := db.ok(); err != nil {
+ return nil, err
+ }
+
+ // The write happen synchronously.
+ select {
+ case db.writeLockC <- struct{}{}:
+ case err := <-db.compPerErrC:
+ return nil, err
+ case _, _ = <-db.closeC:
+ return nil, ErrClosed
+ }
+
+ if db.tr != nil {
+ panic("leveldb: has open transaction")
+ }
+
+ // Flush current memdb.
+ if db.mem != nil && db.mem.Len() != 0 {
+ if _, err := db.rotateMem(0, true); err != nil {
+ return nil, err
+ }
+ }
+
+ tr := &Transaction{
+ db: db,
+ seq: db.seq,
+ mem: db.mpoolGet(0),
+ }
+ tr.mem.incref()
+ db.tr = tr
+ return tr, nil
+}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_util.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_util.go
index a8a2bdf72..8ec86b2ac 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_util.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_util.go
@@ -40,59 +40,59 @@ func (db *DB) checkAndCleanFiles() error {
v := db.s.version()
defer v.release()
- tablesMap := make(map[uint64]bool)
- for _, tables := range v.tables {
+ tmap := make(map[int64]bool)
+ for _, tables := range v.levels {
for _, t := range tables {
- tablesMap[t.file.Num()] = false
+ tmap[t.fd.Num] = false
}
}
- files, err := db.s.getFiles(storage.TypeAll)
+ fds, err := db.s.stor.List(storage.TypeAll)
if err != nil {
return err
}
- var nTables int
- var rem []storage.File
- for _, f := range files {
+ var nt int
+ var rem []storage.FileDesc
+ for _, fd := range fds {
keep := true
- switch f.Type() {
+ switch fd.Type {
case storage.TypeManifest:
- keep = f.Num() >= db.s.manifestFile.Num()
+ keep = fd.Num >= db.s.manifestFd.Num
case storage.TypeJournal:
- if db.frozenJournalFile != nil {
- keep = f.Num() >= db.frozenJournalFile.Num()
+ if !db.frozenJournalFd.Nil() {
+ keep = fd.Num >= db.frozenJournalFd.Num
} else {
- keep = f.Num() >= db.journalFile.Num()
+ keep = fd.Num >= db.journalFd.Num
}
case storage.TypeTable:
- _, keep = tablesMap[f.Num()]
+ _, keep = tmap[fd.Num]
if keep {
- tablesMap[f.Num()] = true
- nTables++
+ tmap[fd.Num] = true
+ nt++
}
}
if !keep {
- rem = append(rem, f)
+ rem = append(rem, fd)
}
}
- if nTables != len(tablesMap) {
- var missing []*storage.FileInfo
- for num, present := range tablesMap {
+ if nt != len(tmap) {
+ var mfds []storage.FileDesc
+ for num, present := range tmap {
if !present {
- missing = append(missing, &storage.FileInfo{Type: storage.TypeTable, Num: num})
+ mfds = append(mfds, storage.FileDesc{storage.TypeTable, num})
db.logf("db@janitor table missing @%d", num)
}
}
- return errors.NewErrCorrupted(nil, &errors.ErrMissingFiles{Files: missing})
+ return errors.NewErrCorrupted(storage.FileDesc{}, &errors.ErrMissingFiles{Fds: mfds})
}
- db.logf("db@janitor F·%d G·%d", len(files), len(rem))
- for _, f := range rem {
- db.logf("db@janitor removing %s-%d", f.Type(), f.Num())
- if err := f.Remove(); err != nil {
+ db.logf("db@janitor F·%d G·%d", len(fds), len(rem))
+ for _, fd := range rem {
+ db.logf("db@janitor removing %s-%d", fd.Type, fd.Num)
+ if err := db.s.stor.Remove(fd); err != nil {
return err
}
}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_write.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_write.go
index e1cf30c53..5200be6fc 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_write.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db_write.go
@@ -45,9 +45,9 @@ func (db *DB) jWriter() {
}
}
-func (db *DB) rotateMem(n int) (mem *memDB, err error) {
+func (db *DB) rotateMem(n int, wait bool) (mem *memDB, err error) {
// Wait for pending memdb compaction.
- err = db.compSendIdle(db.mcompCmdC)
+ err = db.compTriggerWait(db.mcompCmdC)
if err != nil {
return
}
@@ -59,46 +59,50 @@ func (db *DB) rotateMem(n int) (mem *memDB, err error) {
}
// Schedule memdb compaction.
- db.compSendTrigger(db.mcompCmdC)
+ if wait {
+ err = db.compTriggerWait(db.mcompCmdC)
+ } else {
+ db.compTrigger(db.mcompCmdC)
+ }
return
}
-func (db *DB) flush(n int) (mem *memDB, nn int, err error) {
+func (db *DB) flush(n int) (mdb *memDB, mdbFree int, err error) {
delayed := false
flush := func() (retry bool) {
v := db.s.version()
defer v.release()
- mem = db.getEffectiveMem()
+ mdb = db.getEffectiveMem()
defer func() {
if retry {
- mem.decref()
- mem = nil
+ mdb.decref()
+ mdb = nil
}
}()
- nn = mem.mdb.Free()
+ mdbFree = mdb.Free()
switch {
case v.tLen(0) >= db.s.o.GetWriteL0SlowdownTrigger() && !delayed:
delayed = true
time.Sleep(time.Millisecond)
- case nn >= n:
+ case mdbFree >= n:
return false
case v.tLen(0) >= db.s.o.GetWriteL0PauseTrigger():
delayed = true
- err = db.compSendIdle(db.tcompCmdC)
+ err = db.compTriggerWait(db.tcompCmdC)
if err != nil {
return false
}
default:
// Allow memdb to grow if it has no entry.
- if mem.mdb.Len() == 0 {
- nn = n
+ if mdb.Len() == 0 {
+ mdbFree = n
} else {
- mem.decref()
- mem, err = db.rotateMem(n)
+ mdb.decref()
+ mdb, err = db.rotateMem(n, false)
if err == nil {
- nn = mem.mdb.Free()
+ mdbFree = mdb.Free()
} else {
- nn = 0
+ mdbFree = 0
}
}
return false
@@ -129,7 +133,20 @@ func (db *DB) Write(b *Batch, wo *opt.WriteOptions) (err error) {
return
}
- b.init(wo.GetSync())
+ b.init(wo.GetSync() && !db.s.o.GetNoSync())
+
+ if b.size() > db.s.o.GetWriteBuffer() && !db.s.o.GetDisableLargeBatchTransaction() {
+ // Writes using transaction.
+ tr, err1 := db.OpenTransaction()
+ if err1 != nil {
+ return err1
+ }
+ if err1 := tr.Write(b, wo); err1 != nil {
+ tr.Discard()
+ return err1
+ }
+ return tr.Commit()
+ }
// The write happen synchronously.
select {
@@ -137,6 +154,8 @@ func (db *DB) Write(b *Batch, wo *opt.WriteOptions) (err error) {
if <-db.writeMergedC {
return <-db.writeAckC
}
+ // Continue, the write lock already acquired by previous writer
+ // and handed out to us.
case db.writeLockC <- struct{}{}:
case err = <-db.compPerErrC:
return
@@ -148,6 +167,7 @@ func (db *DB) Write(b *Batch, wo *opt.WriteOptions) (err error) {
danglingMerge := false
defer func() {
if danglingMerge {
+ // Only one dangling merge at most, so this is safe.
db.writeMergedC <- false
} else {
<-db.writeLockC
@@ -157,18 +177,18 @@ func (db *DB) Write(b *Batch, wo *opt.WriteOptions) (err error) {
}
}()
- mem, memFree, err := db.flush(b.size())
+ mdb, mdbFree, err := db.flush(b.size())
if err != nil {
return
}
- defer mem.decref()
+ defer mdb.decref()
// Calculate maximum size of the batch.
m := 1 << 20
if x := b.size(); x <= 128<<10 {
m = x + (128 << 10)
}
- m = minInt(m, memFree)
+ m = minInt(m, mdbFree)
// Merge with other batch.
drain:
@@ -197,7 +217,7 @@ drain:
select {
case db.journalC <- b:
// Write into memdb
- if berr := b.memReplay(mem.mdb); berr != nil {
+ if berr := b.memReplay(mdb.DB); berr != nil {
panic(berr)
}
case err = <-db.compPerErrC:
@@ -211,7 +231,7 @@ drain:
case err = <-db.journalAckC:
if err != nil {
// Revert memdb if error detected
- if berr := b.revertMemReplay(mem.mdb); berr != nil {
+ if berr := b.revertMemReplay(mdb.DB); berr != nil {
panic(berr)
}
return
@@ -225,7 +245,7 @@ drain:
if err != nil {
return
}
- if berr := b.memReplay(mem.mdb); berr != nil {
+ if berr := b.memReplay(mdb.DB); berr != nil {
panic(berr)
}
}
@@ -233,8 +253,8 @@ drain:
// Set last seq number.
db.addSeq(uint64(b.Len()))
- if b.size() >= memFree {
- db.rotateMem(0)
+ if b.size() >= mdbFree {
+ db.rotateMem(0, false)
}
return
}
@@ -249,8 +269,7 @@ func (db *DB) Put(key, value []byte, wo *opt.WriteOptions) error {
return db.Write(b, wo)
}
-// Delete deletes the value for the given key. It returns ErrNotFound if
-// the DB does not contain the key.
+// Delete deletes the value for the given key.
//
// It is safe to modify the contents of the arguments after Delete returns.
func (db *DB) Delete(key []byte, wo *opt.WriteOptions) error {
@@ -290,16 +309,16 @@ func (db *DB) CompactRange(r util.Range) error {
}
// Check for overlaps in memdb.
- mem := db.getEffectiveMem()
- defer mem.decref()
- if isMemOverlaps(db.s.icmp, mem.mdb, r.Start, r.Limit) {
+ mdb := db.getEffectiveMem()
+ defer mdb.decref()
+ if isMemOverlaps(db.s.icmp, mdb.DB, r.Start, r.Limit) {
// Memdb compaction.
- if _, err := db.rotateMem(0); err != nil {
+ if _, err := db.rotateMem(0, false); err != nil {
<-db.writeLockC
return err
}
<-db.writeLockC
- if err := db.compSendIdle(db.mcompCmdC); err != nil {
+ if err := db.compTriggerWait(db.mcompCmdC); err != nil {
return err
}
} else {
@@ -307,5 +326,33 @@ func (db *DB) CompactRange(r util.Range) error {
}
// Table compaction.
- return db.compSendRange(db.tcompCmdC, -1, r.Start, r.Limit)
+ return db.compTriggerRange(db.tcompCmdC, -1, r.Start, r.Limit)
+}
+
+// SetReadOnly makes DB read-only. It will stay read-only until reopened.
+func (db *DB) SetReadOnly() error {
+ if err := db.ok(); err != nil {
+ return err
+ }
+
+ // Lock writer.
+ select {
+ case db.writeLockC <- struct{}{}:
+ db.compWriteLocking = true
+ case err := <-db.compPerErrC:
+ return err
+ case _, _ = <-db.closeC:
+ return ErrClosed
+ }
+
+ // Set compaction read-only.
+ select {
+ case db.compErrSetC <- ErrReadOnly:
+ case perr := <-db.compPerErrC:
+ return perr
+ case _, _ = <-db.closeC:
+ return ErrClosed
+ }
+
+ return nil
}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors.go
index 29d0d2f27..c8bd66a5a 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors.go
@@ -12,6 +12,7 @@ import (
var (
ErrNotFound = errors.ErrNotFound
+ ErrReadOnly = errors.New("leveldb: read-only mode")
ErrSnapshotReleased = errors.New("leveldb: snapshot released")
ErrIterReleased = errors.New("leveldb: iterator released")
ErrClosed = errors.New("leveldb: closed")
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors/errors.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors/errors.go
index 84b5d6b7b..9a0f6e2c1 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors/errors.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors/errors.go
@@ -29,21 +29,21 @@ func New(text string) error {
// ErrCorrupted is the type that wraps errors that indicate corruption in
// the database.
type ErrCorrupted struct {
- File *storage.FileInfo
- Err error
+ Fd storage.FileDesc
+ Err error
}
func (e *ErrCorrupted) Error() string {
- if e.File != nil {
- return fmt.Sprintf("%v [file=%v]", e.Err, e.File)
+ if !e.Fd.Nil() {
+ return fmt.Sprintf("%v [file=%v]", e.Err, e.Fd)
} else {
return e.Err.Error()
}
}
// NewErrCorrupted creates new ErrCorrupted error.
-func NewErrCorrupted(f storage.File, err error) error {
- return &ErrCorrupted{storage.NewFileInfo(f), err}
+func NewErrCorrupted(fd storage.FileDesc, err error) error {
+ return &ErrCorrupted{fd, err}
}
// IsCorrupted returns a boolean indicating whether the error is indicating
@@ -52,24 +52,26 @@ func IsCorrupted(err error) bool {
switch err.(type) {
case *ErrCorrupted:
return true
+ case *storage.ErrCorrupted:
+ return true
}
return false
}
// ErrMissingFiles is the type that indicating a corruption due to missing
-// files.
+// files. ErrMissingFiles always wrapped with ErrCorrupted.
type ErrMissingFiles struct {
- Files []*storage.FileInfo
+ Fds []storage.FileDesc
}
func (e *ErrMissingFiles) Error() string { return "file missing" }
-// SetFile sets 'file info' of the given error with the given file.
+// SetFd sets 'file info' of the given error with the given file.
// Currently only ErrCorrupted is supported, otherwise will do nothing.
-func SetFile(err error, f storage.File) error {
+func SetFd(err error, fd storage.FileDesc) error {
switch x := err.(type) {
case *ErrCorrupted:
- x.File = storage.NewFileInfo(f)
+ x.Fd = fd
return x
}
return err
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/external_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/external_test.go
deleted file mode 100644
index b328ece4e..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/external_test.go
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2014, Suryandaru Triandana <syndtr@gmail.com>
-// All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package leveldb
-
-import (
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-
- "github.com/syndtr/goleveldb/leveldb/opt"
- "github.com/syndtr/goleveldb/leveldb/testutil"
-)
-
-var _ = testutil.Defer(func() {
- Describe("Leveldb external", func() {
- o := &opt.Options{
- DisableBlockCache: true,
- BlockRestartInterval: 5,
- BlockSize: 80,
- Compression: opt.NoCompression,
- OpenFilesCacheCapacity: -1,
- Strict: opt.StrictAll,
- WriteBuffer: 1000,
- CompactionTableSize: 2000,
- }
-
- Describe("write test", func() {
- It("should do write correctly", func(done Done) {
- db := newTestingDB(o, nil, nil)
- t := testutil.DBTesting{
- DB: db,
- Deleted: testutil.KeyValue_Generate(nil, 500, 1, 50, 5, 5).Clone(),
- }
- testutil.DoDBTesting(&t)
- db.TestClose()
- done <- true
- }, 20.0)
- })
-
- Describe("read test", func() {
- testutil.AllKeyValueTesting(nil, nil, func(kv testutil.KeyValue) testutil.DB {
- // Building the DB.
- db := newTestingDB(o, nil, nil)
- kv.IterateShuffled(nil, func(i int, key, value []byte) {
- err := db.TestPut(key, value)
- Expect(err).NotTo(HaveOccurred())
- })
-
- return db
- }, func(db testutil.DB) {
- db.(*testingDB).TestClose()
- })
- })
- })
-})
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter/bloom_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter/bloom_test.go
deleted file mode 100644
index 1fb56f071..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter/bloom_test.go
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
-// All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package filter
-
-import (
- "encoding/binary"
- "github.com/syndtr/goleveldb/leveldb/util"
- "testing"
-)
-
-type harness struct {
- t *testing.T
-
- bloom Filter
- generator FilterGenerator
- filter []byte
-}
-
-func newHarness(t *testing.T) *harness {
- bloom := NewBloomFilter(10)
- return &harness{
- t: t,
- bloom: bloom,
- generator: bloom.NewGenerator(),
- }
-}
-
-func (h *harness) add(key []byte) {
- h.generator.Add(key)
-}
-
-func (h *harness) addNum(key uint32) {
- var b [4]byte
- binary.LittleEndian.PutUint32(b[:], key)
- h.add(b[:])
-}
-
-func (h *harness) build() {
- b := &util.Buffer{}
- h.generator.Generate(b)
- h.filter = b.Bytes()
-}
-
-func (h *harness) reset() {
- h.filter = nil
-}
-
-func (h *harness) filterLen() int {
- return len(h.filter)
-}
-
-func (h *harness) assert(key []byte, want, silent bool) bool {
- got := h.bloom.Contains(h.filter, key)
- if !silent && got != want {
- h.t.Errorf("assert on '%v' failed got '%v', want '%v'", key, got, want)
- }
- return got
-}
-
-func (h *harness) assertNum(key uint32, want, silent bool) bool {
- var b [4]byte
- binary.LittleEndian.PutUint32(b[:], key)
- return h.assert(b[:], want, silent)
-}
-
-func TestBloomFilter_Empty(t *testing.T) {
- h := newHarness(t)
- h.build()
- h.assert([]byte("hello"), false, false)
- h.assert([]byte("world"), false, false)
-}
-
-func TestBloomFilter_Small(t *testing.T) {
- h := newHarness(t)
- h.add([]byte("hello"))
- h.add([]byte("world"))
- h.build()
- h.assert([]byte("hello"), true, false)
- h.assert([]byte("world"), true, false)
- h.assert([]byte("x"), false, false)
- h.assert([]byte("foo"), false, false)
-}
-
-func nextN(n int) int {
- switch {
- case n < 10:
- n += 1
- case n < 100:
- n += 10
- case n < 1000:
- n += 100
- default:
- n += 1000
- }
- return n
-}
-
-func TestBloomFilter_VaryingLengths(t *testing.T) {
- h := newHarness(t)
- var mediocre, good int
- for n := 1; n < 10000; n = nextN(n) {
- h.reset()
- for i := 0; i < n; i++ {
- h.addNum(uint32(i))
- }
- h.build()
-
- got := h.filterLen()
- want := (n * 10 / 8) + 40
- if got > want {
- t.Errorf("filter len test failed, '%d' > '%d'", got, want)
- }
-
- for i := 0; i < n; i++ {
- h.assertNum(uint32(i), true, false)
- }
-
- var rate float32
- for i := 0; i < 10000; i++ {
- if h.assertNum(uint32(i+1000000000), true, true) {
- rate++
- }
- }
- rate /= 10000
- if rate > 0.02 {
- t.Errorf("false positive rate is more than 2%%, got %v, at len %d", rate, n)
- }
- if rate > 0.0125 {
- mediocre++
- } else {
- good++
- }
- }
- t.Logf("false positive rate: %d good, %d mediocre", good, mediocre)
- if mediocre > good/5 {
- t.Error("mediocre false positive rate is more than expected")
- }
-}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/array_iter_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/array_iter_test.go
deleted file mode 100644
index 1ed6d07cb..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/array_iter_test.go
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2014, Suryandaru Triandana <syndtr@gmail.com>
-// All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package iterator_test
-
-import (
- . "github.com/onsi/ginkgo"
-
- . "github.com/syndtr/goleveldb/leveldb/iterator"
- "github.com/syndtr/goleveldb/leveldb/testutil"
-)
-
-var _ = testutil.Defer(func() {
- Describe("Array iterator", func() {
- It("Should iterates and seeks correctly", func() {
- // Build key/value.
- kv := testutil.KeyValue_Generate(nil, 70, 1, 5, 3, 3)
-
- // Test the iterator.
- t := testutil.IteratorTesting{
- KeyValue: kv.Clone(),
- Iter: NewArrayIterator(kv),
- }
- testutil.DoIteratorTesting(&t)
- })
- })
-})
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/indexed_iter_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/indexed_iter_test.go
deleted file mode 100644
index 72a797892..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/indexed_iter_test.go
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright (c) 2014, Suryandaru Triandana <syndtr@gmail.com>
-// All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package iterator_test
-
-import (
- "sort"
-
- . "github.com/onsi/ginkgo"
-
- "github.com/syndtr/goleveldb/leveldb/comparer"
- . "github.com/syndtr/goleveldb/leveldb/iterator"
- "github.com/syndtr/goleveldb/leveldb/testutil"
-)
-
-type keyValue struct {
- key []byte
- testutil.KeyValue
-}
-
-type keyValueIndex []keyValue
-
-func (x keyValueIndex) Search(key []byte) int {
- return sort.Search(x.Len(), func(i int) bool {
- return comparer.DefaultComparer.Compare(x[i].key, key) >= 0
- })
-}
-
-func (x keyValueIndex) Len() int { return len(x) }
-func (x keyValueIndex) Index(i int) (key, value []byte) { return x[i].key, nil }
-func (x keyValueIndex) Get(i int) Iterator { return NewArrayIterator(x[i]) }
-
-var _ = testutil.Defer(func() {
- Describe("Indexed iterator", func() {
- Test := func(n ...int) func() {
- if len(n) == 0 {
- rnd := testutil.NewRand()
- n = make([]int, rnd.Intn(17)+3)
- for i := range n {
- n[i] = rnd.Intn(19) + 1
- }
- }
-
- return func() {
- It("Should iterates and seeks correctly", func(done Done) {
- // Build key/value.
- index := make(keyValueIndex, len(n))
- sum := 0
- for _, x := range n {
- sum += x
- }
- kv := testutil.KeyValue_Generate(nil, sum, 1, 10, 4, 4)
- for i, j := 0, 0; i < len(n); i++ {
- for x := n[i]; x > 0; x-- {
- key, value := kv.Index(j)
- index[i].key = key
- index[i].Put(key, value)
- j++
- }
- }
-
- // Test the iterator.
- t := testutil.IteratorTesting{
- KeyValue: kv.Clone(),
- Iter: NewIndexedIterator(NewArrayIndexer(index), true),
- }
- testutil.DoIteratorTesting(&t)
- done <- true
- }, 1.5)
- }
- }
-
- Describe("with 100 keys", Test(100))
- Describe("with 50-50 keys", Test(50, 50))
- Describe("with 50-1 keys", Test(50, 1))
- Describe("with 50-1-50 keys", Test(50, 1, 50))
- Describe("with 1-50 keys", Test(1, 50))
- Describe("with random N-keys", Test())
- })
-})
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/iter_suite_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/iter_suite_test.go
deleted file mode 100644
index 5ef8d5baf..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/iter_suite_test.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package iterator_test
-
-import (
- "testing"
-
- "github.com/syndtr/goleveldb/leveldb/testutil"
-)
-
-func TestIterator(t *testing.T) {
- testutil.RunSuite(t, "Iterator Suite")
-}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/merged_iter_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/merged_iter_test.go
deleted file mode 100644
index e523b63e4..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/iterator/merged_iter_test.go
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright (c) 2014, Suryandaru Triandana <syndtr@gmail.com>
-// All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package iterator_test
-
-import (
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-
- "github.com/syndtr/goleveldb/leveldb/comparer"
- . "github.com/syndtr/goleveldb/leveldb/iterator"
- "github.com/syndtr/goleveldb/leveldb/testutil"
-)
-
-var _ = testutil.Defer(func() {
- Describe("Merged iterator", func() {
- Test := func(filled int, empty int) func() {
- return func() {
- It("Should iterates and seeks correctly", func(done Done) {
- rnd := testutil.NewRand()
-
- // Build key/value.
- filledKV := make([]testutil.KeyValue, filled)
- kv := testutil.KeyValue_Generate(nil, 100, 1, 10, 4, 4)
- kv.Iterate(func(i int, key, value []byte) {
- filledKV[rnd.Intn(filled)].Put(key, value)
- })
-
- // Create itearators.
- iters := make([]Iterator, filled+empty)
- for i := range iters {
- if empty == 0 || (rnd.Int()%2 == 0 && filled > 0) {
- filled--
- Expect(filledKV[filled].Len()).ShouldNot(BeZero())
- iters[i] = NewArrayIterator(filledKV[filled])
- } else {
- empty--
- iters[i] = NewEmptyIterator(nil)
- }
- }
-
- // Test the iterator.
- t := testutil.IteratorTesting{
- KeyValue: kv.Clone(),
- Iter: NewMergedIterator(iters, comparer.DefaultComparer, true),
- }
- testutil.DoIteratorTesting(&t)
- done <- true
- }, 1.5)
- }
- }
-
- Describe("with three, all filled iterators", Test(3, 0))
- Describe("with one filled, one empty iterators", Test(1, 1))
- Describe("with one filled, two empty iterators", Test(1, 2))
- })
-})
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/journal/journal.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/journal/journal.go
index 6519ec660..891098bb7 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/journal/journal.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/journal/journal.go
@@ -83,6 +83,7 @@ import (
"io"
"github.com/syndtr/goleveldb/leveldb/errors"
+ "github.com/syndtr/goleveldb/leveldb/storage"
"github.com/syndtr/goleveldb/leveldb/util"
)
@@ -165,7 +166,7 @@ func (r *Reader) corrupt(n int, reason string, skip bool) error {
r.dropper.Drop(&ErrCorrupted{n, reason})
}
if r.strict && !skip {
- r.err = errors.NewErrCorrupted(nil, &ErrCorrupted{n, reason})
+ r.err = errors.NewErrCorrupted(storage.FileDesc{}, &ErrCorrupted{n, reason})
return r.err
}
return errSkip
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/journal/journal_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/journal/journal_test.go
deleted file mode 100644
index 0fcf22599..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/journal/journal_test.go
+++ /dev/null
@@ -1,818 +0,0 @@
-// Copyright 2011 The LevelDB-Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Taken from: https://code.google.com/p/leveldb-go/source/browse/leveldb/record/record_test.go?r=df1fa28f7f3be6c3935548169002309c12967135
-// License, authors and contributors informations can be found at bellow URLs respectively:
-// https://code.google.com/p/leveldb-go/source/browse/LICENSE
-// https://code.google.com/p/leveldb-go/source/browse/AUTHORS
-// https://code.google.com/p/leveldb-go/source/browse/CONTRIBUTORS
-
-package journal
-
-import (
- "bytes"
- "encoding/binary"
- "fmt"
- "io"
- "io/ioutil"
- "math/rand"
- "strings"
- "testing"
-)
-
-type dropper struct {
- t *testing.T
-}
-
-func (d dropper) Drop(err error) {
- d.t.Log(err)
-}
-
-func short(s string) string {
- if len(s) < 64 {
- return s
- }
- return fmt.Sprintf("%s...(skipping %d bytes)...%s", s[:20], len(s)-40, s[len(s)-20:])
-}
-
-// big returns a string of length n, composed of repetitions of partial.
-func big(partial string, n int) string {
- return strings.Repeat(partial, n/len(partial)+1)[:n]
-}
-
-func TestEmpty(t *testing.T) {
- buf := new(bytes.Buffer)
- r := NewReader(buf, dropper{t}, true, true)
- if _, err := r.Next(); err != io.EOF {
- t.Fatalf("got %v, want %v", err, io.EOF)
- }
-}
-
-func testGenerator(t *testing.T, reset func(), gen func() (string, bool)) {
- buf := new(bytes.Buffer)
-
- reset()
- w := NewWriter(buf)
- for {
- s, ok := gen()
- if !ok {
- break
- }
- ww, err := w.Next()
- if err != nil {
- t.Fatal(err)
- }
- if _, err := ww.Write([]byte(s)); err != nil {
- t.Fatal(err)
- }
- }
- if err := w.Close(); err != nil {
- t.Fatal(err)
- }
-
- reset()
- r := NewReader(buf, dropper{t}, true, true)
- for {
- s, ok := gen()
- if !ok {
- break
- }
- rr, err := r.Next()
- if err != nil {
- t.Fatal(err)
- }
- x, err := ioutil.ReadAll(rr)
- if err != nil {
- t.Fatal(err)
- }
- if string(x) != s {
- t.Fatalf("got %q, want %q", short(string(x)), short(s))
- }
- }
- if _, err := r.Next(); err != io.EOF {
- t.Fatalf("got %v, want %v", err, io.EOF)
- }
-}
-
-func testLiterals(t *testing.T, s []string) {
- var i int
- reset := func() {
- i = 0
- }
- gen := func() (string, bool) {
- if i == len(s) {
- return "", false
- }
- i++
- return s[i-1], true
- }
- testGenerator(t, reset, gen)
-}
-
-func TestMany(t *testing.T) {
- const n = 1e5
- var i int
- reset := func() {
- i = 0
- }
- gen := func() (string, bool) {
- if i == n {
- return "", false
- }
- i++
- return fmt.Sprintf("%d.", i-1), true
- }
- testGenerator(t, reset, gen)
-}
-
-func TestRandom(t *testing.T) {
- const n = 1e2
- var (
- i int
- r *rand.Rand
- )
- reset := func() {
- i, r = 0, rand.New(rand.NewSource(0))
- }
- gen := func() (string, bool) {
- if i == n {
- return "", false
- }
- i++
- return strings.Repeat(string(uint8(i)), r.Intn(2*blockSize+16)), true
- }
- testGenerator(t, reset, gen)
-}
-
-func TestBasic(t *testing.T) {
- testLiterals(t, []string{
- strings.Repeat("a", 1000),
- strings.Repeat("b", 97270),
- strings.Repeat("c", 8000),
- })
-}
-
-func TestBoundary(t *testing.T) {
- for i := blockSize - 16; i < blockSize+16; i++ {
- s0 := big("abcd", i)
- for j := blockSize - 16; j < blockSize+16; j++ {
- s1 := big("ABCDE", j)
- testLiterals(t, []string{s0, s1})
- testLiterals(t, []string{s0, "", s1})
- testLiterals(t, []string{s0, "x", s1})
- }
- }
-}
-
-func TestFlush(t *testing.T) {
- buf := new(bytes.Buffer)
- w := NewWriter(buf)
- // Write a couple of records. Everything should still be held
- // in the record.Writer buffer, so that buf.Len should be 0.
- w0, _ := w.Next()
- w0.Write([]byte("0"))
- w1, _ := w.Next()
- w1.Write([]byte("11"))
- if got, want := buf.Len(), 0; got != want {
- t.Fatalf("buffer length #0: got %d want %d", got, want)
- }
- // Flush the record.Writer buffer, which should yield 17 bytes.
- // 17 = 2*7 + 1 + 2, which is two headers and 1 + 2 payload bytes.
- if err := w.Flush(); err != nil {
- t.Fatal(err)
- }
- if got, want := buf.Len(), 17; got != want {
- t.Fatalf("buffer length #1: got %d want %d", got, want)
- }
- // Do another write, one that isn't large enough to complete the block.
- // The write should not have flowed through to buf.
- w2, _ := w.Next()
- w2.Write(bytes.Repeat([]byte("2"), 10000))
- if got, want := buf.Len(), 17; got != want {
- t.Fatalf("buffer length #2: got %d want %d", got, want)
- }
- // Flushing should get us up to 10024 bytes written.
- // 10024 = 17 + 7 + 10000.
- if err := w.Flush(); err != nil {
- t.Fatal(err)
- }
- if got, want := buf.Len(), 10024; got != want {
- t.Fatalf("buffer length #3: got %d want %d", got, want)
- }
- // Do a bigger write, one that completes the current block.
- // We should now have 32768 bytes (a complete block), without
- // an explicit flush.
- w3, _ := w.Next()
- w3.Write(bytes.Repeat([]byte("3"), 40000))
- if got, want := buf.Len(), 32768; got != want {
- t.Fatalf("buffer length #4: got %d want %d", got, want)
- }
- // Flushing should get us up to 50038 bytes written.
- // 50038 = 10024 + 2*7 + 40000. There are two headers because
- // the one record was split into two chunks.
- if err := w.Flush(); err != nil {
- t.Fatal(err)
- }
- if got, want := buf.Len(), 50038; got != want {
- t.Fatalf("buffer length #5: got %d want %d", got, want)
- }
- // Check that reading those records give the right lengths.
- r := NewReader(buf, dropper{t}, true, true)
- wants := []int64{1, 2, 10000, 40000}
- for i, want := range wants {
- rr, _ := r.Next()
- n, err := io.Copy(ioutil.Discard, rr)
- if err != nil {
- t.Fatalf("read #%d: %v", i, err)
- }
- if n != want {
- t.Fatalf("read #%d: got %d bytes want %d", i, n, want)
- }
- }
-}
-
-func TestNonExhaustiveRead(t *testing.T) {
- const n = 100
- buf := new(bytes.Buffer)
- p := make([]byte, 10)
- rnd := rand.New(rand.NewSource(1))
-
- w := NewWriter(buf)
- for i := 0; i < n; i++ {
- length := len(p) + rnd.Intn(3*blockSize)
- s := string(uint8(i)) + "123456789abcdefgh"
- ww, _ := w.Next()
- ww.Write([]byte(big(s, length)))
- }
- if err := w.Close(); err != nil {
- t.Fatal(err)
- }
-
- r := NewReader(buf, dropper{t}, true, true)
- for i := 0; i < n; i++ {
- rr, _ := r.Next()
- _, err := io.ReadFull(rr, p)
- if err != nil {
- t.Fatal(err)
- }
- want := string(uint8(i)) + "123456789"
- if got := string(p); got != want {
- t.Fatalf("read #%d: got %q want %q", i, got, want)
- }
- }
-}
-
-func TestStaleReader(t *testing.T) {
- buf := new(bytes.Buffer)
-
- w := NewWriter(buf)
- w0, err := w.Next()
- if err != nil {
- t.Fatal(err)
- }
- w0.Write([]byte("0"))
- w1, err := w.Next()
- if err != nil {
- t.Fatal(err)
- }
- w1.Write([]byte("11"))
- if err := w.Close(); err != nil {
- t.Fatal(err)
- }
-
- r := NewReader(buf, dropper{t}, true, true)
- r0, err := r.Next()
- if err != nil {
- t.Fatal(err)
- }
- r1, err := r.Next()
- if err != nil {
- t.Fatal(err)
- }
- p := make([]byte, 1)
- if _, err := r0.Read(p); err == nil || !strings.Contains(err.Error(), "stale") {
- t.Fatalf("stale read #0: unexpected error: %v", err)
- }
- if _, err := r1.Read(p); err != nil {
- t.Fatalf("fresh read #1: got %v want nil error", err)
- }
- if p[0] != '1' {
- t.Fatalf("fresh read #1: byte contents: got '%c' want '1'", p[0])
- }
-}
-
-func TestStaleWriter(t *testing.T) {
- buf := new(bytes.Buffer)
-
- w := NewWriter(buf)
- w0, err := w.Next()
- if err != nil {
- t.Fatal(err)
- }
- w1, err := w.Next()
- if err != nil {
- t.Fatal(err)
- }
- if _, err := w0.Write([]byte("0")); err == nil || !strings.Contains(err.Error(), "stale") {
- t.Fatalf("stale write #0: unexpected error: %v", err)
- }
- if _, err := w1.Write([]byte("11")); err != nil {
- t.Fatalf("fresh write #1: got %v want nil error", err)
- }
- if err := w.Flush(); err != nil {
- t.Fatalf("flush: %v", err)
- }
- if _, err := w1.Write([]byte("0")); err == nil || !strings.Contains(err.Error(), "stale") {
- t.Fatalf("stale write #1: unexpected error: %v", err)
- }
-}
-
-func TestCorrupt_MissingLastBlock(t *testing.T) {
- buf := new(bytes.Buffer)
-
- w := NewWriter(buf)
-
- // First record.
- ww, err := w.Next()
- if err != nil {
- t.Fatal(err)
- }
- if _, err := ww.Write(bytes.Repeat([]byte("0"), blockSize-1024)); err != nil {
- t.Fatalf("write #0: unexpected error: %v", err)
- }
-
- // Second record.
- ww, err = w.Next()
- if err != nil {
- t.Fatal(err)
- }
- if _, err := ww.Write(bytes.Repeat([]byte("0"), blockSize-headerSize)); err != nil {
- t.Fatalf("write #1: unexpected error: %v", err)
- }
-
- if err := w.Close(); err != nil {
- t.Fatal(err)
- }
-
- // Cut the last block.
- b := buf.Bytes()[:blockSize]
- r := NewReader(bytes.NewReader(b), dropper{t}, false, true)
-
- // First read.
- rr, err := r.Next()
- if err != nil {
- t.Fatal(err)
- }
- n, err := io.Copy(ioutil.Discard, rr)
- if err != nil {
- t.Fatalf("read #0: %v", err)
- }
- if n != blockSize-1024 {
- t.Fatalf("read #0: got %d bytes want %d", n, blockSize-1024)
- }
-
- // Second read.
- rr, err = r.Next()
- if err != nil {
- t.Fatal(err)
- }
- n, err = io.Copy(ioutil.Discard, rr)
- if err != io.ErrUnexpectedEOF {
- t.Fatalf("read #1: unexpected error: %v", err)
- }
-
- if _, err := r.Next(); err != io.EOF {
- t.Fatalf("last next: unexpected error: %v", err)
- }
-}
-
-func TestCorrupt_CorruptedFirstBlock(t *testing.T) {
- buf := new(bytes.Buffer)
-
- w := NewWriter(buf)
-
- // First record.
- ww, err := w.Next()
- if err != nil {
- t.Fatal(err)
- }
- if _, err := ww.Write(bytes.Repeat([]byte("0"), blockSize/2)); err != nil {
- t.Fatalf("write #0: unexpected error: %v", err)
- }
-
- // Second record.
- ww, err = w.Next()
- if err != nil {
- t.Fatal(err)
- }
- if _, err := ww.Write(bytes.Repeat([]byte("0"), blockSize-headerSize)); err != nil {
- t.Fatalf("write #1: unexpected error: %v", err)
- }
-
- // Third record.
- ww, err = w.Next()
- if err != nil {
- t.Fatal(err)
- }
- if _, err := ww.Write(bytes.Repeat([]byte("0"), (blockSize-headerSize)+1)); err != nil {
- t.Fatalf("write #2: unexpected error: %v", err)
- }
-
- // Fourth record.
- ww, err = w.Next()
- if err != nil {
- t.Fatal(err)
- }
- if _, err := ww.Write(bytes.Repeat([]byte("0"), (blockSize-headerSize)+2)); err != nil {
- t.Fatalf("write #3: unexpected error: %v", err)
- }
-
- if err := w.Close(); err != nil {
- t.Fatal(err)
- }
-
- b := buf.Bytes()
- // Corrupting block #0.
- for i := 0; i < 1024; i++ {
- b[i] = '1'
- }
-
- r := NewReader(bytes.NewReader(b), dropper{t}, false, true)
-
- // First read (third record).
- rr, err := r.Next()
- if err != nil {
- t.Fatal(err)
- }
- n, err := io.Copy(ioutil.Discard, rr)
- if err != nil {
- t.Fatalf("read #0: %v", err)
- }
- if want := int64(blockSize-headerSize) + 1; n != want {
- t.Fatalf("read #0: got %d bytes want %d", n, want)
- }
-
- // Second read (fourth record).
- rr, err = r.Next()
- if err != nil {
- t.Fatal(err)
- }
- n, err = io.Copy(ioutil.Discard, rr)
- if err != nil {
- t.Fatalf("read #1: %v", err)
- }
- if want := int64(blockSize-headerSize) + 2; n != want {
- t.Fatalf("read #1: got %d bytes want %d", n, want)
- }
-
- if _, err := r.Next(); err != io.EOF {
- t.Fatalf("last next: unexpected error: %v", err)
- }
-}
-
-func TestCorrupt_CorruptedMiddleBlock(t *testing.T) {
- buf := new(bytes.Buffer)
-
- w := NewWriter(buf)
-
- // First record.
- ww, err := w.Next()
- if err != nil {
- t.Fatal(err)
- }
- if _, err := ww.Write(bytes.Repeat([]byte("0"), blockSize/2)); err != nil {
- t.Fatalf("write #0: unexpected error: %v", err)
- }
-
- // Second record.
- ww, err = w.Next()
- if err != nil {
- t.Fatal(err)
- }
- if _, err := ww.Write(bytes.Repeat([]byte("0"), blockSize-headerSize)); err != nil {
- t.Fatalf("write #1: unexpected error: %v", err)
- }
-
- // Third record.
- ww, err = w.Next()
- if err != nil {
- t.Fatal(err)
- }
- if _, err := ww.Write(bytes.Repeat([]byte("0"), (blockSize-headerSize)+1)); err != nil {
- t.Fatalf("write #2: unexpected error: %v", err)
- }
-
- // Fourth record.
- ww, err = w.Next()
- if err != nil {
- t.Fatal(err)
- }
- if _, err := ww.Write(bytes.Repeat([]byte("0"), (blockSize-headerSize)+2)); err != nil {
- t.Fatalf("write #3: unexpected error: %v", err)
- }
-
- if err := w.Close(); err != nil {
- t.Fatal(err)
- }
-
- b := buf.Bytes()
- // Corrupting block #1.
- for i := 0; i < 1024; i++ {
- b[blockSize+i] = '1'
- }
-
- r := NewReader(bytes.NewReader(b), dropper{t}, false, true)
-
- // First read (first record).
- rr, err := r.Next()
- if err != nil {
- t.Fatal(err)
- }
- n, err := io.Copy(ioutil.Discard, rr)
- if err != nil {
- t.Fatalf("read #0: %v", err)
- }
- if want := int64(blockSize / 2); n != want {
- t.Fatalf("read #0: got %d bytes want %d", n, want)
- }
-
- // Second read (second record).
- rr, err = r.Next()
- if err != nil {
- t.Fatal(err)
- }
- n, err = io.Copy(ioutil.Discard, rr)
- if err != io.ErrUnexpectedEOF {
- t.Fatalf("read #1: unexpected error: %v", err)
- }
-
- // Third read (fourth record).
- rr, err = r.Next()
- if err != nil {
- t.Fatal(err)
- }
- n, err = io.Copy(ioutil.Discard, rr)
- if err != nil {
- t.Fatalf("read #2: %v", err)
- }
- if want := int64(blockSize-headerSize) + 2; n != want {
- t.Fatalf("read #2: got %d bytes want %d", n, want)
- }
-
- if _, err := r.Next(); err != io.EOF {
- t.Fatalf("last next: unexpected error: %v", err)
- }
-}
-
-func TestCorrupt_CorruptedLastBlock(t *testing.T) {
- buf := new(bytes.Buffer)
-
- w := NewWriter(buf)
-
- // First record.
- ww, err := w.Next()
- if err != nil {
- t.Fatal(err)
- }
- if _, err := ww.Write(bytes.Repeat([]byte("0"), blockSize/2)); err != nil {
- t.Fatalf("write #0: unexpected error: %v", err)
- }
-
- // Second record.
- ww, err = w.Next()
- if err != nil {
- t.Fatal(err)
- }
- if _, err := ww.Write(bytes.Repeat([]byte("0"), blockSize-headerSize)); err != nil {
- t.Fatalf("write #1: unexpected error: %v", err)
- }
-
- // Third record.
- ww, err = w.Next()
- if err != nil {
- t.Fatal(err)
- }
- if _, err := ww.Write(bytes.Repeat([]byte("0"), (blockSize-headerSize)+1)); err != nil {
- t.Fatalf("write #2: unexpected error: %v", err)
- }
-
- // Fourth record.
- ww, err = w.Next()
- if err != nil {
- t.Fatal(err)
- }
- if _, err := ww.Write(bytes.Repeat([]byte("0"), (blockSize-headerSize)+2)); err != nil {
- t.Fatalf("write #3: unexpected error: %v", err)
- }
-
- if err := w.Close(); err != nil {
- t.Fatal(err)
- }
-
- b := buf.Bytes()
- // Corrupting block #3.
- for i := len(b) - 1; i > len(b)-1024; i-- {
- b[i] = '1'
- }
-
- r := NewReader(bytes.NewReader(b), dropper{t}, false, true)
-
- // First read (first record).
- rr, err := r.Next()
- if err != nil {
- t.Fatal(err)
- }
- n, err := io.Copy(ioutil.Discard, rr)
- if err != nil {
- t.Fatalf("read #0: %v", err)
- }
- if want := int64(blockSize / 2); n != want {
- t.Fatalf("read #0: got %d bytes want %d", n, want)
- }
-
- // Second read (second record).
- rr, err = r.Next()
- if err != nil {
- t.Fatal(err)
- }
- n, err = io.Copy(ioutil.Discard, rr)
- if err != nil {
- t.Fatalf("read #1: %v", err)
- }
- if want := int64(blockSize - headerSize); n != want {
- t.Fatalf("read #1: got %d bytes want %d", n, want)
- }
-
- // Third read (third record).
- rr, err = r.Next()
- if err != nil {
- t.Fatal(err)
- }
- n, err = io.Copy(ioutil.Discard, rr)
- if err != nil {
- t.Fatalf("read #2: %v", err)
- }
- if want := int64(blockSize-headerSize) + 1; n != want {
- t.Fatalf("read #2: got %d bytes want %d", n, want)
- }
-
- // Fourth read (fourth record).
- rr, err = r.Next()
- if err != nil {
- t.Fatal(err)
- }
- n, err = io.Copy(ioutil.Discard, rr)
- if err != io.ErrUnexpectedEOF {
- t.Fatalf("read #3: unexpected error: %v", err)
- }
-
- if _, err := r.Next(); err != io.EOF {
- t.Fatalf("last next: unexpected error: %v", err)
- }
-}
-
-func TestCorrupt_FirstChuckLengthOverflow(t *testing.T) {
- buf := new(bytes.Buffer)
-
- w := NewWriter(buf)
-
- // First record.
- ww, err := w.Next()
- if err != nil {
- t.Fatal(err)
- }
- if _, err := ww.Write(bytes.Repeat([]byte("0"), blockSize/2)); err != nil {
- t.Fatalf("write #0: unexpected error: %v", err)
- }
-
- // Second record.
- ww, err = w.Next()
- if err != nil {
- t.Fatal(err)
- }
- if _, err := ww.Write(bytes.Repeat([]byte("0"), blockSize-headerSize)); err != nil {
- t.Fatalf("write #1: unexpected error: %v", err)
- }
-
- // Third record.
- ww, err = w.Next()
- if err != nil {
- t.Fatal(err)
- }
- if _, err := ww.Write(bytes.Repeat([]byte("0"), (blockSize-headerSize)+1)); err != nil {
- t.Fatalf("write #2: unexpected error: %v", err)
- }
-
- if err := w.Close(); err != nil {
- t.Fatal(err)
- }
-
- b := buf.Bytes()
- // Corrupting record #1.
- x := blockSize
- binary.LittleEndian.PutUint16(b[x+4:], 0xffff)
-
- r := NewReader(bytes.NewReader(b), dropper{t}, false, true)
-
- // First read (first record).
- rr, err := r.Next()
- if err != nil {
- t.Fatal(err)
- }
- n, err := io.Copy(ioutil.Discard, rr)
- if err != nil {
- t.Fatalf("read #0: %v", err)
- }
- if want := int64(blockSize / 2); n != want {
- t.Fatalf("read #0: got %d bytes want %d", n, want)
- }
-
- // Second read (second record).
- rr, err = r.Next()
- if err != nil {
- t.Fatal(err)
- }
- n, err = io.Copy(ioutil.Discard, rr)
- if err != io.ErrUnexpectedEOF {
- t.Fatalf("read #1: unexpected error: %v", err)
- }
-
- if _, err := r.Next(); err != io.EOF {
- t.Fatalf("last next: unexpected error: %v", err)
- }
-}
-
-func TestCorrupt_MiddleChuckLengthOverflow(t *testing.T) {
- buf := new(bytes.Buffer)
-
- w := NewWriter(buf)
-
- // First record.
- ww, err := w.Next()
- if err != nil {
- t.Fatal(err)
- }
- if _, err := ww.Write(bytes.Repeat([]byte("0"), blockSize/2)); err != nil {
- t.Fatalf("write #0: unexpected error: %v", err)
- }
-
- // Second record.
- ww, err = w.Next()
- if err != nil {
- t.Fatal(err)
- }
- if _, err := ww.Write(bytes.Repeat([]byte("0"), blockSize-headerSize)); err != nil {
- t.Fatalf("write #1: unexpected error: %v", err)
- }
-
- // Third record.
- ww, err = w.Next()
- if err != nil {
- t.Fatal(err)
- }
- if _, err := ww.Write(bytes.Repeat([]byte("0"), (blockSize-headerSize)+1)); err != nil {
- t.Fatalf("write #2: unexpected error: %v", err)
- }
-
- if err := w.Close(); err != nil {
- t.Fatal(err)
- }
-
- b := buf.Bytes()
- // Corrupting record #1.
- x := blockSize/2 + headerSize
- binary.LittleEndian.PutUint16(b[x+4:], 0xffff)
-
- r := NewReader(bytes.NewReader(b), dropper{t}, false, true)
-
- // First read (first record).
- rr, err := r.Next()
- if err != nil {
- t.Fatal(err)
- }
- n, err := io.Copy(ioutil.Discard, rr)
- if err != nil {
- t.Fatalf("read #0: %v", err)
- }
- if want := int64(blockSize / 2); n != want {
- t.Fatalf("read #0: got %d bytes want %d", n, want)
- }
-
- // Second read (third record).
- rr, err = r.Next()
- if err != nil {
- t.Fatal(err)
- }
- n, err = io.Copy(ioutil.Discard, rr)
- if err != nil {
- t.Fatalf("read #1: %v", err)
- }
- if want := int64(blockSize-headerSize) + 1; n != want {
- t.Fatalf("read #1: got %d bytes want %d", n, want)
- }
-
- if _, err := r.Next(); err != io.EOF {
- t.Fatalf("last next: unexpected error: %v", err)
- }
-}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/key.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/key.go
index 572ae8150..1443c7526 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/key.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/key.go
@@ -11,6 +11,7 @@ import (
"fmt"
"github.com/syndtr/goleveldb/leveldb/errors"
+ "github.com/syndtr/goleveldb/leveldb/storage"
)
type ErrIkeyCorrupted struct {
@@ -23,7 +24,7 @@ func (e *ErrIkeyCorrupted) Error() string {
}
func newErrIkeyCorrupted(ikey []byte, reason string) error {
- return errors.NewErrCorrupted(nil, &ErrIkeyCorrupted{append([]byte{}, ikey...), reason})
+ return errors.NewErrCorrupted(storage.FileDesc{}, &ErrIkeyCorrupted{append([]byte{}, ikey...), reason})
}
type kType int
@@ -70,17 +71,21 @@ func init() {
type iKey []byte
-func newIkey(ukey []byte, seq uint64, kt kType) iKey {
+func makeIkey(dst, ukey []byte, seq uint64, kt kType) iKey {
if seq > kMaxSeq {
panic("leveldb: invalid sequence number")
} else if kt > ktVal {
panic("leveldb: invalid type")
}
- ik := make(iKey, len(ukey)+8)
- copy(ik, ukey)
- binary.LittleEndian.PutUint64(ik[len(ukey):], (seq<<8)|uint64(kt))
- return ik
+ if n := len(ukey) + 8; cap(dst) < n {
+ dst = make([]byte, n)
+ } else {
+ dst = dst[:n]
+ }
+ copy(dst, ukey)
+ binary.LittleEndian.PutUint64(dst[len(ukey):], (seq<<8)|uint64(kt))
+ return iKey(dst)
}
func parseIkey(ik []byte) (ukey []byte, seq uint64, kt kType, err error) {
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/key_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/key_test.go
deleted file mode 100644
index 30eadf784..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/key_test.go
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
-// All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package leveldb
-
-import (
- "bytes"
- "testing"
-
- "github.com/syndtr/goleveldb/leveldb/comparer"
-)
-
-var defaultIComparer = &iComparer{comparer.DefaultComparer}
-
-func ikey(key string, seq uint64, kt kType) iKey {
- return newIkey([]byte(key), uint64(seq), kt)
-}
-
-func shortSep(a, b []byte) []byte {
- dst := make([]byte, len(a))
- dst = defaultIComparer.Separator(dst[:0], a, b)
- if dst == nil {
- return a
- }
- return dst
-}
-
-func shortSuccessor(b []byte) []byte {
- dst := make([]byte, len(b))
- dst = defaultIComparer.Successor(dst[:0], b)
- if dst == nil {
- return b
- }
- return dst
-}
-
-func testSingleKey(t *testing.T, key string, seq uint64, kt kType) {
- ik := ikey(key, seq, kt)
-
- if !bytes.Equal(ik.ukey(), []byte(key)) {
- t.Errorf("user key does not equal, got %v, want %v", string(ik.ukey()), key)
- }
-
- rseq, rt := ik.parseNum()
- if rseq != seq {
- t.Errorf("seq number does not equal, got %v, want %v", rseq, seq)
- }
- if rt != kt {
- t.Errorf("type does not equal, got %v, want %v", rt, kt)
- }
-
- if rukey, rseq, rt, kerr := parseIkey(ik); kerr == nil {
- if !bytes.Equal(rukey, []byte(key)) {
- t.Errorf("user key does not equal, got %v, want %v", string(ik.ukey()), key)
- }
- if rseq != seq {
- t.Errorf("seq number does not equal, got %v, want %v", rseq, seq)
- }
- if rt != kt {
- t.Errorf("type does not equal, got %v, want %v", rt, kt)
- }
- } else {
- t.Errorf("key error: %v", kerr)
- }
-}
-
-func TestIkey_EncodeDecode(t *testing.T) {
- keys := []string{"", "k", "hello", "longggggggggggggggggggggg"}
- seqs := []uint64{
- 1, 2, 3,
- (1 << 8) - 1, 1 << 8, (1 << 8) + 1,
- (1 << 16) - 1, 1 << 16, (1 << 16) + 1,
- (1 << 32) - 1, 1 << 32, (1 << 32) + 1,
- }
- for _, key := range keys {
- for _, seq := range seqs {
- testSingleKey(t, key, seq, ktVal)
- testSingleKey(t, "hello", 1, ktDel)
- }
- }
-}
-
-func assertBytes(t *testing.T, want, got []byte) {
- if !bytes.Equal(got, want) {
- t.Errorf("assert failed, got %v, want %v", got, want)
- }
-}
-
-func TestIkeyShortSeparator(t *testing.T) {
- // When user keys are same
- assertBytes(t, ikey("foo", 100, ktVal),
- shortSep(ikey("foo", 100, ktVal),
- ikey("foo", 99, ktVal)))
- assertBytes(t, ikey("foo", 100, ktVal),
- shortSep(ikey("foo", 100, ktVal),
- ikey("foo", 101, ktVal)))
- assertBytes(t, ikey("foo", 100, ktVal),
- shortSep(ikey("foo", 100, ktVal),
- ikey("foo", 100, ktVal)))
- assertBytes(t, ikey("foo", 100, ktVal),
- shortSep(ikey("foo", 100, ktVal),
- ikey("foo", 100, ktDel)))
-
- // When user keys are misordered
- assertBytes(t, ikey("foo", 100, ktVal),
- shortSep(ikey("foo", 100, ktVal),
- ikey("bar", 99, ktVal)))
-
- // When user keys are different, but correctly ordered
- assertBytes(t, ikey("g", uint64(kMaxSeq), ktSeek),
- shortSep(ikey("foo", 100, ktVal),
- ikey("hello", 200, ktVal)))
-
- // When start user key is prefix of limit user key
- assertBytes(t, ikey("foo", 100, ktVal),
- shortSep(ikey("foo", 100, ktVal),
- ikey("foobar", 200, ktVal)))
-
- // When limit user key is prefix of start user key
- assertBytes(t, ikey("foobar", 100, ktVal),
- shortSep(ikey("foobar", 100, ktVal),
- ikey("foo", 200, ktVal)))
-}
-
-func TestIkeyShortestSuccessor(t *testing.T) {
- assertBytes(t, ikey("g", uint64(kMaxSeq), ktSeek),
- shortSuccessor(ikey("foo", 100, ktVal)))
- assertBytes(t, ikey("\xff\xff", 100, ktVal),
- shortSuccessor(ikey("\xff\xff", 100, ktVal)))
-}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/leveldb_suite_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/leveldb_suite_test.go
deleted file mode 100644
index fefa007a7..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/leveldb_suite_test.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package leveldb
-
-import (
- "testing"
-
- "github.com/syndtr/goleveldb/leveldb/testutil"
-)
-
-func TestLevelDB(t *testing.T) {
- testutil.RunSuite(t, "LevelDB Suite")
-}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/bench_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/bench_test.go
deleted file mode 100644
index b05084caa..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/bench_test.go
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
-// All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package memdb
-
-import (
- "encoding/binary"
- "math/rand"
- "testing"
-
- "github.com/syndtr/goleveldb/leveldb/comparer"
-)
-
-func BenchmarkPut(b *testing.B) {
- buf := make([][4]byte, b.N)
- for i := range buf {
- binary.LittleEndian.PutUint32(buf[i][:], uint32(i))
- }
-
- b.ResetTimer()
- p := New(comparer.DefaultComparer, 0)
- for i := range buf {
- p.Put(buf[i][:], nil)
- }
-}
-
-func BenchmarkPutRandom(b *testing.B) {
- buf := make([][4]byte, b.N)
- for i := range buf {
- binary.LittleEndian.PutUint32(buf[i][:], uint32(rand.Int()))
- }
-
- b.ResetTimer()
- p := New(comparer.DefaultComparer, 0)
- for i := range buf {
- p.Put(buf[i][:], nil)
- }
-}
-
-func BenchmarkGet(b *testing.B) {
- buf := make([][4]byte, b.N)
- for i := range buf {
- binary.LittleEndian.PutUint32(buf[i][:], uint32(i))
- }
-
- p := New(comparer.DefaultComparer, 0)
- for i := range buf {
- p.Put(buf[i][:], nil)
- }
-
- b.ResetTimer()
- for i := range buf {
- p.Get(buf[i][:])
- }
-}
-
-func BenchmarkGetRandom(b *testing.B) {
- buf := make([][4]byte, b.N)
- for i := range buf {
- binary.LittleEndian.PutUint32(buf[i][:], uint32(i))
- }
-
- p := New(comparer.DefaultComparer, 0)
- for i := range buf {
- p.Put(buf[i][:], nil)
- }
-
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- p.Get(buf[rand.Int()%b.N][:])
- }
-}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb.go
index e5398873b..1395bd928 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb.go
@@ -206,6 +206,7 @@ func (p *DB) randHeight() (h int) {
return
}
+// Must hold RW-lock if prev == true, as it use shared prevNode slice.
func (p *DB) findGE(key []byte, prev bool) (int, bool) {
node := 0
h := p.maxHeight - 1
@@ -302,7 +303,7 @@ func (p *DB) Put(key []byte, value []byte) error {
node := len(p.nodeData)
p.nodeData = append(p.nodeData, kvOffset, len(key), len(value), h)
for i, n := range p.prevNode[:h] {
- m := n + 4 + i
+ m := n + nNext + i
p.nodeData = append(p.nodeData, p.nodeData[m])
p.nodeData[m] = node
}
@@ -434,20 +435,22 @@ func (p *DB) Len() int {
// Reset resets the DB to initial empty state. Allows reuse the buffer.
func (p *DB) Reset() {
+ p.mu.Lock()
p.rnd = rand.New(rand.NewSource(0xdeadbeef))
p.maxHeight = 1
p.n = 0
p.kvSize = 0
p.kvData = p.kvData[:0]
- p.nodeData = p.nodeData[:4+tMaxHeight]
+ p.nodeData = p.nodeData[:nNext+tMaxHeight]
p.nodeData[nKV] = 0
p.nodeData[nKey] = 0
p.nodeData[nVal] = 0
p.nodeData[nHeight] = tMaxHeight
for n := 0; n < tMaxHeight; n++ {
- p.nodeData[4+n] = 0
+ p.nodeData[nNext+n] = 0
p.prevNode[n] = 0
}
+ p.mu.Unlock()
}
// New creates a new initalized in-memory key/value DB. The capacity
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb_suite_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb_suite_test.go
deleted file mode 100644
index 18c304b7f..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb_suite_test.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package memdb
-
-import (
- "testing"
-
- "github.com/syndtr/goleveldb/leveldb/testutil"
-)
-
-func TestMemDB(t *testing.T) {
- testutil.RunSuite(t, "MemDB Suite")
-}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb_test.go
deleted file mode 100644
index 5dd6dbc7b..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/memdb/memdb_test.go
+++ /dev/null
@@ -1,135 +0,0 @@
-// Copyright (c) 2014, Suryandaru Triandana <syndtr@gmail.com>
-// All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package memdb
-
-import (
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-
- "github.com/syndtr/goleveldb/leveldb/comparer"
- "github.com/syndtr/goleveldb/leveldb/iterator"
- "github.com/syndtr/goleveldb/leveldb/testutil"
- "github.com/syndtr/goleveldb/leveldb/util"
-)
-
-func (p *DB) TestFindLT(key []byte) (rkey, value []byte, err error) {
- p.mu.RLock()
- if node := p.findLT(key); node != 0 {
- n := p.nodeData[node]
- m := n + p.nodeData[node+nKey]
- rkey = p.kvData[n:m]
- value = p.kvData[m : m+p.nodeData[node+nVal]]
- } else {
- err = ErrNotFound
- }
- p.mu.RUnlock()
- return
-}
-
-func (p *DB) TestFindLast() (rkey, value []byte, err error) {
- p.mu.RLock()
- if node := p.findLast(); node != 0 {
- n := p.nodeData[node]
- m := n + p.nodeData[node+nKey]
- rkey = p.kvData[n:m]
- value = p.kvData[m : m+p.nodeData[node+nVal]]
- } else {
- err = ErrNotFound
- }
- p.mu.RUnlock()
- return
-}
-
-func (p *DB) TestPut(key []byte, value []byte) error {
- p.Put(key, value)
- return nil
-}
-
-func (p *DB) TestDelete(key []byte) error {
- p.Delete(key)
- return nil
-}
-
-func (p *DB) TestFind(key []byte) (rkey, rvalue []byte, err error) {
- return p.Find(key)
-}
-
-func (p *DB) TestGet(key []byte) (value []byte, err error) {
- return p.Get(key)
-}
-
-func (p *DB) TestNewIterator(slice *util.Range) iterator.Iterator {
- return p.NewIterator(slice)
-}
-
-var _ = testutil.Defer(func() {
- Describe("Memdb", func() {
- Describe("write test", func() {
- It("should do write correctly", func() {
- db := New(comparer.DefaultComparer, 0)
- t := testutil.DBTesting{
- DB: db,
- Deleted: testutil.KeyValue_Generate(nil, 1000, 1, 30, 5, 5).Clone(),
- PostFn: func(t *testutil.DBTesting) {
- Expect(db.Len()).Should(Equal(t.Present.Len()))
- Expect(db.Size()).Should(Equal(t.Present.Size()))
- switch t.Act {
- case testutil.DBPut, testutil.DBOverwrite:
- Expect(db.Contains(t.ActKey)).Should(BeTrue())
- default:
- Expect(db.Contains(t.ActKey)).Should(BeFalse())
- }
- },
- }
- testutil.DoDBTesting(&t)
- })
- })
-
- Describe("read test", func() {
- testutil.AllKeyValueTesting(nil, func(kv testutil.KeyValue) testutil.DB {
- // Building the DB.
- db := New(comparer.DefaultComparer, 0)
- kv.IterateShuffled(nil, func(i int, key, value []byte) {
- db.Put(key, value)
- })
-
- if kv.Len() > 1 {
- It("Should find correct keys with findLT", func() {
- testutil.ShuffledIndex(nil, kv.Len()-1, 1, func(i int) {
- key_, key, _ := kv.IndexInexact(i + 1)
- expectedKey, expectedValue := kv.Index(i)
-
- // Using key that exist.
- rkey, rvalue, err := db.TestFindLT(key)
- Expect(err).ShouldNot(HaveOccurred(), "Error for key %q -> %q", key, expectedKey)
- Expect(rkey).Should(Equal(expectedKey), "Key")
- Expect(rvalue).Should(Equal(expectedValue), "Value for key %q -> %q", key, expectedKey)
-
- // Using key that doesn't exist.
- rkey, rvalue, err = db.TestFindLT(key_)
- Expect(err).ShouldNot(HaveOccurred(), "Error for key %q (%q) -> %q", key_, key, expectedKey)
- Expect(rkey).Should(Equal(expectedKey))
- Expect(rvalue).Should(Equal(expectedValue), "Value for key %q (%q) -> %q", key_, key, expectedKey)
- })
- })
- }
-
- if kv.Len() > 0 {
- It("Should find last key with findLast", func() {
- key, value := kv.Index(kv.Len() - 1)
- rkey, rvalue, err := db.TestFindLast()
- Expect(err).ShouldNot(HaveOccurred())
- Expect(rkey).Should(Equal(key))
- Expect(rvalue).Should(Equal(value))
- })
- }
-
- return db
- }, nil, nil)
- })
- })
-})
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt/options.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt/options.go
index 61f0eadf9..3d2bf1c02 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt/options.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt/options.go
@@ -8,10 +8,11 @@
package opt
import (
+ "math"
+
"github.com/syndtr/goleveldb/leveldb/cache"
"github.com/syndtr/goleveldb/leveldb/comparer"
"github.com/syndtr/goleveldb/leveldb/filter"
- "math"
)
const (
@@ -35,8 +36,6 @@ var (
DefaultCompactionTotalSizeMultiplier = 10.0
DefaultCompressionType = SnappyCompression
DefaultIteratorSamplingRate = 1 * MiB
- DefaultMaxMemCompationLevel = 2
- DefaultNumLevel = 7
DefaultOpenFilesCacher = LRUCacher
DefaultOpenFilesCacheCapacity = 500
DefaultWriteBuffer = 4 * MiB
@@ -250,6 +249,11 @@ type Options struct {
// The default value (DefaultCompression) uses snappy compression.
Compression Compression
+ // DisableBufferPool allows disable use of util.BufferPool functionality.
+ //
+ // The default value is false.
+ DisableBufferPool bool
+
// DisableBlockCache allows disable use of cache.Cache functionality on
// 'sorted table' block.
//
@@ -261,6 +265,13 @@ type Options struct {
// The default value is false.
DisableCompactionBackoff bool
+ // DisableLargeBatchTransaction allows disabling switch-to-transaction mode
+ // on large batch write. If enable batch writes large than WriteBuffer will
+ // use transaction.
+ //
+ // The default is false.
+ DisableLargeBatchTransaction bool
+
// ErrorIfExist defines whether an error should returned if the DB already
// exist.
//
@@ -296,18 +307,10 @@ type Options struct {
// The default is 1MiB.
IteratorSamplingRate int
- // MaxMemCompationLevel defines maximum level a newly compacted 'memdb'
- // will be pushed into if doesn't creates overlap. This should less than
- // NumLevel. Use -1 for level-0.
+ // NoSync allows completely disable fsync.
//
- // The default is 2.
- MaxMemCompationLevel int
-
- // NumLevel defines number of database level. The level shouldn't changed
- // between opens, or the database will panic.
- //
- // The default is 7.
- NumLevel int
+ // The default is false.
+ NoSync bool
// OpenFilesCacher provides cache algorithm for open files caching.
// Specify NoCacher to disable caching algorithm.
@@ -321,6 +324,11 @@ type Options struct {
// The default value is 500.
OpenFilesCacheCapacity int
+ // If true then opens DB in read-only mode.
+ //
+ // The default value is false.
+ ReadOnly bool
+
// Strict defines the DB strict level.
Strict Strict
@@ -425,7 +433,7 @@ func (o *Options) GetCompactionTableSize(level int) int {
if o.CompactionTableSize > 0 {
base = o.CompactionTableSize
}
- if len(o.CompactionTableSizeMultiplierPerLevel) > level && o.CompactionTableSizeMultiplierPerLevel[level] > 0 {
+ if level < len(o.CompactionTableSizeMultiplierPerLevel) && o.CompactionTableSizeMultiplierPerLevel[level] > 0 {
mult = o.CompactionTableSizeMultiplierPerLevel[level]
} else if o.CompactionTableSizeMultiplier > 0 {
mult = math.Pow(o.CompactionTableSizeMultiplier, float64(level))
@@ -446,7 +454,7 @@ func (o *Options) GetCompactionTotalSize(level int) int64 {
if o.CompactionTotalSize > 0 {
base = o.CompactionTotalSize
}
- if len(o.CompactionTotalSizeMultiplierPerLevel) > level && o.CompactionTotalSizeMultiplierPerLevel[level] > 0 {
+ if level < len(o.CompactionTotalSizeMultiplierPerLevel) && o.CompactionTotalSizeMultiplierPerLevel[level] > 0 {
mult = o.CompactionTotalSizeMultiplierPerLevel[level]
} else if o.CompactionTotalSizeMultiplier > 0 {
mult = math.Pow(o.CompactionTotalSizeMultiplier, float64(level))
@@ -472,6 +480,20 @@ func (o *Options) GetCompression() Compression {
return o.Compression
}
+func (o *Options) GetDisableBufferPool() bool {
+ if o == nil {
+ return false
+ }
+ return o.DisableBufferPool
+}
+
+func (o *Options) GetDisableBlockCache() bool {
+ if o == nil {
+ return false
+ }
+ return o.DisableBlockCache
+}
+
func (o *Options) GetDisableCompactionBackoff() bool {
if o == nil {
return false
@@ -479,6 +501,13 @@ func (o *Options) GetDisableCompactionBackoff() bool {
return o.DisableCompactionBackoff
}
+func (o *Options) GetDisableLargeBatchTransaction() bool {
+ if o == nil {
+ return false
+ }
+ return o.DisableLargeBatchTransaction
+}
+
func (o *Options) GetErrorIfExist() bool {
if o == nil {
return false
@@ -507,26 +536,11 @@ func (o *Options) GetIteratorSamplingRate() int {
return o.IteratorSamplingRate
}
-func (o *Options) GetMaxMemCompationLevel() int {
- level := DefaultMaxMemCompationLevel
- if o != nil {
- if o.MaxMemCompationLevel > 0 {
- level = o.MaxMemCompationLevel
- } else if o.MaxMemCompationLevel < 0 {
- level = 0
- }
- }
- if level >= o.GetNumLevel() {
- return o.GetNumLevel() - 1
- }
- return level
-}
-
-func (o *Options) GetNumLevel() int {
- if o == nil || o.NumLevel <= 0 {
- return DefaultNumLevel
+func (o *Options) GetNoSync() bool {
+ if o == nil {
+ return false
}
- return o.NumLevel
+ return o.NoSync
}
func (o *Options) GetOpenFilesCacher() Cacher {
@@ -548,6 +562,13 @@ func (o *Options) GetOpenFilesCacheCapacity() int {
return o.OpenFilesCacheCapacity
}
+func (o *Options) GetReadOnly() bool {
+ if o == nil {
+ return false
+ }
+ return o.ReadOnly
+}
+
func (o *Options) GetStrict(strict Strict) bool {
if o == nil || o.Strict == 0 {
return DefaultStrict&strict != 0
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/options.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/options.go
index a3d84ef60..b072b1ac4 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/options.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/options.go
@@ -43,6 +43,8 @@ func (s *session) setOptions(o *opt.Options) {
s.o.cache()
}
+const optCachedLevel = 7
+
type cachedOptions struct {
*opt.Options
@@ -54,15 +56,13 @@ type cachedOptions struct {
}
func (co *cachedOptions) cache() {
- numLevel := co.Options.GetNumLevel()
-
- co.compactionExpandLimit = make([]int, numLevel)
- co.compactionGPOverlaps = make([]int, numLevel)
- co.compactionSourceLimit = make([]int, numLevel)
- co.compactionTableSize = make([]int, numLevel)
- co.compactionTotalSize = make([]int64, numLevel)
+ co.compactionExpandLimit = make([]int, optCachedLevel)
+ co.compactionGPOverlaps = make([]int, optCachedLevel)
+ co.compactionSourceLimit = make([]int, optCachedLevel)
+ co.compactionTableSize = make([]int, optCachedLevel)
+ co.compactionTotalSize = make([]int64, optCachedLevel)
- for level := 0; level < numLevel; level++ {
+ for level := 0; level < optCachedLevel; level++ {
co.compactionExpandLimit[level] = co.Options.GetCompactionExpandLimit(level)
co.compactionGPOverlaps[level] = co.Options.GetCompactionGPOverlaps(level)
co.compactionSourceLimit[level] = co.Options.GetCompactionSourceLimit(level)
@@ -72,21 +72,36 @@ func (co *cachedOptions) cache() {
}
func (co *cachedOptions) GetCompactionExpandLimit(level int) int {
- return co.compactionExpandLimit[level]
+ if level < optCachedLevel {
+ return co.compactionExpandLimit[level]
+ }
+ return co.Options.GetCompactionExpandLimit(level)
}
func (co *cachedOptions) GetCompactionGPOverlaps(level int) int {
- return co.compactionGPOverlaps[level]
+ if level < optCachedLevel {
+ return co.compactionGPOverlaps[level]
+ }
+ return co.Options.GetCompactionGPOverlaps(level)
}
func (co *cachedOptions) GetCompactionSourceLimit(level int) int {
- return co.compactionSourceLimit[level]
+ if level < optCachedLevel {
+ return co.compactionSourceLimit[level]
+ }
+ return co.Options.GetCompactionSourceLimit(level)
}
func (co *cachedOptions) GetCompactionTableSize(level int) int {
- return co.compactionTableSize[level]
+ if level < optCachedLevel {
+ return co.compactionTableSize[level]
+ }
+ return co.Options.GetCompactionTableSize(level)
}
func (co *cachedOptions) GetCompactionTotalSize(level int) int64 {
- return co.compactionTotalSize[level]
+ if level < optCachedLevel {
+ return co.compactionTotalSize[level]
+ }
+ return co.Options.GetCompactionTotalSize(level)
}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session.go
index b3906f7fc..a8d7b54dc 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session.go
@@ -11,14 +11,11 @@ import (
"io"
"os"
"sync"
- "sync/atomic"
"github.com/syndtr/goleveldb/leveldb/errors"
- "github.com/syndtr/goleveldb/leveldb/iterator"
"github.com/syndtr/goleveldb/leveldb/journal"
"github.com/syndtr/goleveldb/leveldb/opt"
"github.com/syndtr/goleveldb/leveldb/storage"
- "github.com/syndtr/goleveldb/leveldb/util"
)
type ErrManifestCorrupted struct {
@@ -30,28 +27,28 @@ func (e *ErrManifestCorrupted) Error() string {
return fmt.Sprintf("leveldb: manifest corrupted (field '%s'): %s", e.Field, e.Reason)
}
-func newErrManifestCorrupted(f storage.File, field, reason string) error {
- return errors.NewErrCorrupted(f, &ErrManifestCorrupted{field, reason})
+func newErrManifestCorrupted(fd storage.FileDesc, field, reason string) error {
+ return errors.NewErrCorrupted(fd, &ErrManifestCorrupted{field, reason})
}
// session represent a persistent database session.
type session struct {
// Need 64-bit alignment.
- stNextFileNum uint64 // current unused file number
- stJournalNum uint64 // current journal file number; need external synchronization
- stPrevJournalNum uint64 // prev journal file number; no longer used; for compatibility with older version of leveldb
+ stNextFileNum int64 // current unused file number
+ stJournalNum int64 // current journal file number; need external synchronization
+ stPrevJournalNum int64 // prev journal file number; no longer used; for compatibility with older version of leveldb
+ stTempFileNum int64
stSeqNum uint64 // last mem compacted seq; need external synchronization
- stTempFileNum uint64
stor storage.Storage
- storLock util.Releaser
+ storLock storage.Lock
o *cachedOptions
icmp *iComparer
tops *tOps
manifest *journal.Writer
manifestWriter storage.Writer
- manifestFile storage.File
+ manifestFd storage.FileDesc
stCompPtrs []iKey // compaction pointers; need external synchronization
stVersion *version // current version
@@ -68,9 +65,8 @@ func newSession(stor storage.Storage, o *opt.Options) (s *session, err error) {
return
}
s = &session{
- stor: stor,
- storLock: storLock,
- stCompPtrs: make([]iKey, o.GetNumLevel()),
+ stor: stor,
+ storLock: storLock,
}
s.setOptions(o)
s.tops = newTableOps(s)
@@ -90,7 +86,6 @@ func (s *session) close() {
}
s.manifest = nil
s.manifestWriter = nil
- s.manifestFile = nil
s.stVersion = nil
}
@@ -111,27 +106,31 @@ func (s *session) recover() (err error) {
if os.IsNotExist(err) {
// Don't return os.ErrNotExist if the underlying storage contains
// other files that belong to LevelDB. So the DB won't get trashed.
- if files, _ := s.stor.GetFiles(storage.TypeAll); len(files) > 0 {
- err = &errors.ErrCorrupted{File: &storage.FileInfo{Type: storage.TypeManifest}, Err: &errors.ErrMissingFiles{}}
+ if fds, _ := s.stor.List(storage.TypeAll); len(fds) > 0 {
+ err = &errors.ErrCorrupted{Fd: storage.FileDesc{Type: storage.TypeManifest}, Err: &errors.ErrMissingFiles{}}
}
}
}()
- m, err := s.stor.GetManifest()
+ fd, err := s.stor.GetMeta()
if err != nil {
return
}
- reader, err := m.Open()
+ reader, err := s.stor.Open(fd)
if err != nil {
return
}
defer reader.Close()
- strict := s.o.GetStrict(opt.StrictManifest)
- jr := journal.NewReader(reader, dropper{s, m}, strict, true)
- staging := s.stVersion.newStaging()
- rec := &sessionRecord{numLevel: s.o.GetNumLevel()}
+ var (
+ // Options.
+ strict = s.o.GetStrict(opt.StrictManifest)
+
+ jr = journal.NewReader(reader, dropper{s, fd}, strict, true)
+ rec = &sessionRecord{}
+ staging = s.stVersion.newStaging()
+ )
for {
var r io.Reader
r, err = jr.Next()
@@ -140,23 +139,23 @@ func (s *session) recover() (err error) {
err = nil
break
}
- return errors.SetFile(err, m)
+ return errors.SetFd(err, fd)
}
err = rec.decode(r)
if err == nil {
// save compact pointers
for _, r := range rec.compPtrs {
- s.stCompPtrs[r.level] = iKey(r.ikey)
+ s.setCompPtr(r.level, iKey(r.ikey))
}
// commit record to version staging
staging.commit(rec)
} else {
- err = errors.SetFile(err, m)
+ err = errors.SetFd(err, fd)
if strict || !errors.IsCorrupted(err) {
return
} else {
- s.logf("manifest error: %v (skipped)", errors.SetFile(err, m))
+ s.logf("manifest error: %v (skipped)", errors.SetFd(err, fd))
}
}
rec.resetCompPtrs()
@@ -166,18 +165,18 @@ func (s *session) recover() (err error) {
switch {
case !rec.has(recComparer):
- return newErrManifestCorrupted(m, "comparer", "missing")
+ return newErrManifestCorrupted(fd, "comparer", "missing")
case rec.comparer != s.icmp.uName():
- return newErrManifestCorrupted(m, "comparer", fmt.Sprintf("mismatch: want '%s', got '%s'", s.icmp.uName(), rec.comparer))
+ return newErrManifestCorrupted(fd, "comparer", fmt.Sprintf("mismatch: want '%s', got '%s'", s.icmp.uName(), rec.comparer))
case !rec.has(recNextFileNum):
- return newErrManifestCorrupted(m, "next-file-num", "missing")
+ return newErrManifestCorrupted(fd, "next-file-num", "missing")
case !rec.has(recJournalNum):
- return newErrManifestCorrupted(m, "journal-file-num", "missing")
+ return newErrManifestCorrupted(fd, "journal-file-num", "missing")
case !rec.has(recSeqNum):
- return newErrManifestCorrupted(m, "seq-num", "missing")
+ return newErrManifestCorrupted(fd, "seq-num", "missing")
}
- s.manifestFile = m
+ s.manifestFd = fd
s.setVersion(staging.finish())
s.setNextFileNum(rec.nextFileNum)
s.recordCommited(rec)
@@ -206,250 +205,3 @@ func (s *session) commit(r *sessionRecord) (err error) {
return
}
-
-// Pick a compaction based on current state; need external synchronization.
-func (s *session) pickCompaction() *compaction {
- v := s.version()
-
- var level int
- var t0 tFiles
- if v.cScore >= 1 {
- level = v.cLevel
- cptr := s.stCompPtrs[level]
- tables := v.tables[level]
- for _, t := range tables {
- if cptr == nil || s.icmp.Compare(t.imax, cptr) > 0 {
- t0 = append(t0, t)
- break
- }
- }
- if len(t0) == 0 {
- t0 = append(t0, tables[0])
- }
- } else {
- if p := atomic.LoadPointer(&v.cSeek); p != nil {
- ts := (*tSet)(p)
- level = ts.level
- t0 = append(t0, ts.table)
- } else {
- v.release()
- return nil
- }
- }
-
- return newCompaction(s, v, level, t0)
-}
-
-// Create compaction from given level and range; need external synchronization.
-func (s *session) getCompactionRange(level int, umin, umax []byte) *compaction {
- v := s.version()
-
- t0 := v.tables[level].getOverlaps(nil, s.icmp, umin, umax, level == 0)
- if len(t0) == 0 {
- v.release()
- return nil
- }
-
- // Avoid compacting too much in one shot in case the range is large.
- // But we cannot do this for level-0 since level-0 files can overlap
- // and we must not pick one file and drop another older file if the
- // two files overlap.
- if level > 0 {
- limit := uint64(v.s.o.GetCompactionSourceLimit(level))
- total := uint64(0)
- for i, t := range t0 {
- total += t.size
- if total >= limit {
- s.logf("table@compaction limiting F·%d -> F·%d", len(t0), i+1)
- t0 = t0[:i+1]
- break
- }
- }
- }
-
- return newCompaction(s, v, level, t0)
-}
-
-func newCompaction(s *session, v *version, level int, t0 tFiles) *compaction {
- c := &compaction{
- s: s,
- v: v,
- level: level,
- tables: [2]tFiles{t0, nil},
- maxGPOverlaps: uint64(s.o.GetCompactionGPOverlaps(level)),
- tPtrs: make([]int, s.o.GetNumLevel()),
- }
- c.expand()
- c.save()
- return c
-}
-
-// compaction represent a compaction state.
-type compaction struct {
- s *session
- v *version
-
- level int
- tables [2]tFiles
- maxGPOverlaps uint64
-
- gp tFiles
- gpi int
- seenKey bool
- gpOverlappedBytes uint64
- imin, imax iKey
- tPtrs []int
- released bool
-
- snapGPI int
- snapSeenKey bool
- snapGPOverlappedBytes uint64
- snapTPtrs []int
-}
-
-func (c *compaction) save() {
- c.snapGPI = c.gpi
- c.snapSeenKey = c.seenKey
- c.snapGPOverlappedBytes = c.gpOverlappedBytes
- c.snapTPtrs = append(c.snapTPtrs[:0], c.tPtrs...)
-}
-
-func (c *compaction) restore() {
- c.gpi = c.snapGPI
- c.seenKey = c.snapSeenKey
- c.gpOverlappedBytes = c.snapGPOverlappedBytes
- c.tPtrs = append(c.tPtrs[:0], c.snapTPtrs...)
-}
-
-func (c *compaction) release() {
- if !c.released {
- c.released = true
- c.v.release()
- }
-}
-
-// Expand compacted tables; need external synchronization.
-func (c *compaction) expand() {
- limit := uint64(c.s.o.GetCompactionExpandLimit(c.level))
- vt0, vt1 := c.v.tables[c.level], c.v.tables[c.level+1]
-
- t0, t1 := c.tables[0], c.tables[1]
- imin, imax := t0.getRange(c.s.icmp)
- // We expand t0 here just incase ukey hop across tables.
- t0 = vt0.getOverlaps(t0, c.s.icmp, imin.ukey(), imax.ukey(), c.level == 0)
- if len(t0) != len(c.tables[0]) {
- imin, imax = t0.getRange(c.s.icmp)
- }
- t1 = vt1.getOverlaps(t1, c.s.icmp, imin.ukey(), imax.ukey(), false)
- // Get entire range covered by compaction.
- amin, amax := append(t0, t1...).getRange(c.s.icmp)
-
- // See if we can grow the number of inputs in "level" without
- // changing the number of "level+1" files we pick up.
- if len(t1) > 0 {
- exp0 := vt0.getOverlaps(nil, c.s.icmp, amin.ukey(), amax.ukey(), c.level == 0)
- if len(exp0) > len(t0) && t1.size()+exp0.size() < limit {
- xmin, xmax := exp0.getRange(c.s.icmp)
- exp1 := vt1.getOverlaps(nil, c.s.icmp, xmin.ukey(), xmax.ukey(), false)
- if len(exp1) == len(t1) {
- c.s.logf("table@compaction expanding L%d+L%d (F·%d S·%s)+(F·%d S·%s) -> (F·%d S·%s)+(F·%d S·%s)",
- c.level, c.level+1, len(t0), shortenb(int(t0.size())), len(t1), shortenb(int(t1.size())),
- len(exp0), shortenb(int(exp0.size())), len(exp1), shortenb(int(exp1.size())))
- imin, imax = xmin, xmax
- t0, t1 = exp0, exp1
- amin, amax = append(t0, t1...).getRange(c.s.icmp)
- }
- }
- }
-
- // Compute the set of grandparent files that overlap this compaction
- // (parent == level+1; grandparent == level+2)
- if c.level+2 < c.s.o.GetNumLevel() {
- c.gp = c.v.tables[c.level+2].getOverlaps(c.gp, c.s.icmp, amin.ukey(), amax.ukey(), false)
- }
-
- c.tables[0], c.tables[1] = t0, t1
- c.imin, c.imax = imin, imax
-}
-
-// Check whether compaction is trivial.
-func (c *compaction) trivial() bool {
- return len(c.tables[0]) == 1 && len(c.tables[1]) == 0 && c.gp.size() <= c.maxGPOverlaps
-}
-
-func (c *compaction) baseLevelForKey(ukey []byte) bool {
- for level, tables := range c.v.tables[c.level+2:] {
- for c.tPtrs[level] < len(tables) {
- t := tables[c.tPtrs[level]]
- if c.s.icmp.uCompare(ukey, t.imax.ukey()) <= 0 {
- // We've advanced far enough.
- if c.s.icmp.uCompare(ukey, t.imin.ukey()) >= 0 {
- // Key falls in this file's range, so definitely not base level.
- return false
- }
- break
- }
- c.tPtrs[level]++
- }
- }
- return true
-}
-
-func (c *compaction) shouldStopBefore(ikey iKey) bool {
- for ; c.gpi < len(c.gp); c.gpi++ {
- gp := c.gp[c.gpi]
- if c.s.icmp.Compare(ikey, gp.imax) <= 0 {
- break
- }
- if c.seenKey {
- c.gpOverlappedBytes += gp.size
- }
- }
- c.seenKey = true
-
- if c.gpOverlappedBytes > c.maxGPOverlaps {
- // Too much overlap for current output; start new output.
- c.gpOverlappedBytes = 0
- return true
- }
- return false
-}
-
-// Creates an iterator.
-func (c *compaction) newIterator() iterator.Iterator {
- // Creates iterator slice.
- icap := len(c.tables)
- if c.level == 0 {
- // Special case for level-0
- icap = len(c.tables[0]) + 1
- }
- its := make([]iterator.Iterator, 0, icap)
-
- // Options.
- ro := &opt.ReadOptions{
- DontFillCache: true,
- Strict: opt.StrictOverride,
- }
- strict := c.s.o.GetStrict(opt.StrictCompaction)
- if strict {
- ro.Strict |= opt.StrictReader
- }
-
- for i, tables := range c.tables {
- if len(tables) == 0 {
- continue
- }
-
- // Level-0 is not sorted and may overlaps each other.
- if c.level+i == 0 {
- for _, t := range tables {
- its = append(its, c.s.tops.newIterator(t, nil, ro))
- }
- } else {
- it := iterator.NewIndexedIterator(tables.newIndexIterator(c.s.tops, c.s.icmp, nil, ro), strict)
- its = append(its, it)
- }
- }
-
- return iterator.NewMergedIterator(its, c.s.icmp, strict)
-}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_compaction.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_compaction.go
new file mode 100644
index 000000000..471d68d56
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_compaction.go
@@ -0,0 +1,302 @@
+// Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
+// All rights reserved.
+//
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package leveldb
+
+import (
+ "sync/atomic"
+
+ "github.com/syndtr/goleveldb/leveldb/iterator"
+ "github.com/syndtr/goleveldb/leveldb/memdb"
+ "github.com/syndtr/goleveldb/leveldb/opt"
+)
+
+func (s *session) pickMemdbLevel(umin, umax []byte, maxLevel int) int {
+ v := s.version()
+ defer v.release()
+ return v.pickMemdbLevel(umin, umax, maxLevel)
+}
+
+func (s *session) flushMemdb(rec *sessionRecord, mdb *memdb.DB, maxLevel int) (int, error) {
+ // Create sorted table.
+ iter := mdb.NewIterator(nil)
+ defer iter.Release()
+ t, n, err := s.tops.createFrom(iter)
+ if err != nil {
+ return 0, err
+ }
+
+ // Pick level other than zero can cause compaction issue with large
+ // bulk insert and delete on strictly incrementing key-space. The
+ // problem is that the small deletion markers trapped at lower level,
+ // while key/value entries keep growing at higher level. Since the
+ // key-space is strictly incrementing it will not overlaps with
+ // higher level, thus maximum possible level is always picked, while
+ // overlapping deletion marker pushed into lower level.
+ // See: https://github.com/syndtr/goleveldb/issues/127.
+ flushLevel := s.pickMemdbLevel(t.imin.ukey(), t.imax.ukey(), maxLevel)
+ rec.addTableFile(flushLevel, t)
+
+ s.logf("memdb@flush created L%d@%d N·%d S·%s %q:%q", flushLevel, t.fd.Num, n, shortenb(int(t.size)), t.imin, t.imax)
+ return flushLevel, nil
+}
+
+// Pick a compaction based on current state; need external synchronization.
+func (s *session) pickCompaction() *compaction {
+ v := s.version()
+
+ var sourceLevel int
+ var t0 tFiles
+ if v.cScore >= 1 {
+ sourceLevel = v.cLevel
+ cptr := s.getCompPtr(sourceLevel)
+ tables := v.levels[sourceLevel]
+ for _, t := range tables {
+ if cptr == nil || s.icmp.Compare(t.imax, cptr) > 0 {
+ t0 = append(t0, t)
+ break
+ }
+ }
+ if len(t0) == 0 {
+ t0 = append(t0, tables[0])
+ }
+ } else {
+ if p := atomic.LoadPointer(&v.cSeek); p != nil {
+ ts := (*tSet)(p)
+ sourceLevel = ts.level
+ t0 = append(t0, ts.table)
+ } else {
+ v.release()
+ return nil
+ }
+ }
+
+ return newCompaction(s, v, sourceLevel, t0)
+}
+
+// Create compaction from given level and range; need external synchronization.
+func (s *session) getCompactionRange(sourceLevel int, umin, umax []byte, noLimit bool) *compaction {
+ v := s.version()
+
+ if sourceLevel >= len(v.levels) {
+ v.release()
+ return nil
+ }
+
+ t0 := v.levels[sourceLevel].getOverlaps(nil, s.icmp, umin, umax, sourceLevel == 0)
+ if len(t0) == 0 {
+ v.release()
+ return nil
+ }
+
+ // Avoid compacting too much in one shot in case the range is large.
+ // But we cannot do this for level-0 since level-0 files can overlap
+ // and we must not pick one file and drop another older file if the
+ // two files overlap.
+ if !noLimit && sourceLevel > 0 {
+ limit := int64(v.s.o.GetCompactionSourceLimit(sourceLevel))
+ total := int64(0)
+ for i, t := range t0 {
+ total += t.size
+ if total >= limit {
+ s.logf("table@compaction limiting F·%d -> F·%d", len(t0), i+1)
+ t0 = t0[:i+1]
+ break
+ }
+ }
+ }
+
+ return newCompaction(s, v, sourceLevel, t0)
+}
+
+func newCompaction(s *session, v *version, sourceLevel int, t0 tFiles) *compaction {
+ c := &compaction{
+ s: s,
+ v: v,
+ sourceLevel: sourceLevel,
+ levels: [2]tFiles{t0, nil},
+ maxGPOverlaps: int64(s.o.GetCompactionGPOverlaps(sourceLevel)),
+ tPtrs: make([]int, len(v.levels)),
+ }
+ c.expand()
+ c.save()
+ return c
+}
+
+// compaction represent a compaction state.
+type compaction struct {
+ s *session
+ v *version
+
+ sourceLevel int
+ levels [2]tFiles
+ maxGPOverlaps int64
+
+ gp tFiles
+ gpi int
+ seenKey bool
+ gpOverlappedBytes int64
+ imin, imax iKey
+ tPtrs []int
+ released bool
+
+ snapGPI int
+ snapSeenKey bool
+ snapGPOverlappedBytes int64
+ snapTPtrs []int
+}
+
+func (c *compaction) save() {
+ c.snapGPI = c.gpi
+ c.snapSeenKey = c.seenKey
+ c.snapGPOverlappedBytes = c.gpOverlappedBytes
+ c.snapTPtrs = append(c.snapTPtrs[:0], c.tPtrs...)
+}
+
+func (c *compaction) restore() {
+ c.gpi = c.snapGPI
+ c.seenKey = c.snapSeenKey
+ c.gpOverlappedBytes = c.snapGPOverlappedBytes
+ c.tPtrs = append(c.tPtrs[:0], c.snapTPtrs...)
+}
+
+func (c *compaction) release() {
+ if !c.released {
+ c.released = true
+ c.v.release()
+ }
+}
+
+// Expand compacted tables; need external synchronization.
+func (c *compaction) expand() {
+ limit := int64(c.s.o.GetCompactionExpandLimit(c.sourceLevel))
+ vt0 := c.v.levels[c.sourceLevel]
+ vt1 := tFiles{}
+ if level := c.sourceLevel + 1; level < len(c.v.levels) {
+ vt1 = c.v.levels[level]
+ }
+
+ t0, t1 := c.levels[0], c.levels[1]
+ imin, imax := t0.getRange(c.s.icmp)
+ // We expand t0 here just incase ukey hop across tables.
+ t0 = vt0.getOverlaps(t0, c.s.icmp, imin.ukey(), imax.ukey(), c.sourceLevel == 0)
+ if len(t0) != len(c.levels[0]) {
+ imin, imax = t0.getRange(c.s.icmp)
+ }
+ t1 = vt1.getOverlaps(t1, c.s.icmp, imin.ukey(), imax.ukey(), false)
+ // Get entire range covered by compaction.
+ amin, amax := append(t0, t1...).getRange(c.s.icmp)
+
+ // See if we can grow the number of inputs in "sourceLevel" without
+ // changing the number of "sourceLevel+1" files we pick up.
+ if len(t1) > 0 {
+ exp0 := vt0.getOverlaps(nil, c.s.icmp, amin.ukey(), amax.ukey(), c.sourceLevel == 0)
+ if len(exp0) > len(t0) && t1.size()+exp0.size() < limit {
+ xmin, xmax := exp0.getRange(c.s.icmp)
+ exp1 := vt1.getOverlaps(nil, c.s.icmp, xmin.ukey(), xmax.ukey(), false)
+ if len(exp1) == len(t1) {
+ c.s.logf("table@compaction expanding L%d+L%d (F·%d S·%s)+(F·%d S·%s) -> (F·%d S·%s)+(F·%d S·%s)",
+ c.sourceLevel, c.sourceLevel+1, len(t0), shortenb(int(t0.size())), len(t1), shortenb(int(t1.size())),
+ len(exp0), shortenb(int(exp0.size())), len(exp1), shortenb(int(exp1.size())))
+ imin, imax = xmin, xmax
+ t0, t1 = exp0, exp1
+ amin, amax = append(t0, t1...).getRange(c.s.icmp)
+ }
+ }
+ }
+
+ // Compute the set of grandparent files that overlap this compaction
+ // (parent == sourceLevel+1; grandparent == sourceLevel+2)
+ if level := c.sourceLevel + 2; level < len(c.v.levels) {
+ c.gp = c.v.levels[level].getOverlaps(c.gp, c.s.icmp, amin.ukey(), amax.ukey(), false)
+ }
+
+ c.levels[0], c.levels[1] = t0, t1
+ c.imin, c.imax = imin, imax
+}
+
+// Check whether compaction is trivial.
+func (c *compaction) trivial() bool {
+ return len(c.levels[0]) == 1 && len(c.levels[1]) == 0 && c.gp.size() <= c.maxGPOverlaps
+}
+
+func (c *compaction) baseLevelForKey(ukey []byte) bool {
+ for level := c.sourceLevel + 2; level < len(c.v.levels); level++ {
+ tables := c.v.levels[level]
+ for c.tPtrs[level] < len(tables) {
+ t := tables[c.tPtrs[level]]
+ if c.s.icmp.uCompare(ukey, t.imax.ukey()) <= 0 {
+ // We've advanced far enough.
+ if c.s.icmp.uCompare(ukey, t.imin.ukey()) >= 0 {
+ // Key falls in this file's range, so definitely not base level.
+ return false
+ }
+ break
+ }
+ c.tPtrs[level]++
+ }
+ }
+ return true
+}
+
+func (c *compaction) shouldStopBefore(ikey iKey) bool {
+ for ; c.gpi < len(c.gp); c.gpi++ {
+ gp := c.gp[c.gpi]
+ if c.s.icmp.Compare(ikey, gp.imax) <= 0 {
+ break
+ }
+ if c.seenKey {
+ c.gpOverlappedBytes += gp.size
+ }
+ }
+ c.seenKey = true
+
+ if c.gpOverlappedBytes > c.maxGPOverlaps {
+ // Too much overlap for current output; start new output.
+ c.gpOverlappedBytes = 0
+ return true
+ }
+ return false
+}
+
+// Creates an iterator.
+func (c *compaction) newIterator() iterator.Iterator {
+ // Creates iterator slice.
+ icap := len(c.levels)
+ if c.sourceLevel == 0 {
+ // Special case for level-0.
+ icap = len(c.levels[0]) + 1
+ }
+ its := make([]iterator.Iterator, 0, icap)
+
+ // Options.
+ ro := &opt.ReadOptions{
+ DontFillCache: true,
+ Strict: opt.StrictOverride,
+ }
+ strict := c.s.o.GetStrict(opt.StrictCompaction)
+ if strict {
+ ro.Strict |= opt.StrictReader
+ }
+
+ for i, tables := range c.levels {
+ if len(tables) == 0 {
+ continue
+ }
+
+ // Level-0 is not sorted and may overlaps each other.
+ if c.sourceLevel+i == 0 {
+ for _, t := range tables {
+ its = append(its, c.s.tops.newIterator(t, nil, ro))
+ }
+ } else {
+ it := iterator.NewIndexedIterator(tables.newIndexIterator(c.s.tops, c.s.icmp, nil, ro), strict)
+ its = append(its, it)
+ }
+ }
+
+ return iterator.NewMergedIterator(its, c.s.icmp, strict)
+}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_record.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_record.go
index 1bdcc68f5..9802e1a55 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_record.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_record.go
@@ -13,6 +13,7 @@ import (
"strings"
"github.com/syndtr/goleveldb/leveldb/errors"
+ "github.com/syndtr/goleveldb/leveldb/storage"
)
type byteReader interface {
@@ -40,25 +41,23 @@ type cpRecord struct {
type atRecord struct {
level int
- num uint64
- size uint64
+ num int64
+ size int64
imin iKey
imax iKey
}
type dtRecord struct {
level int
- num uint64
+ num int64
}
type sessionRecord struct {
- numLevel int
-
hasRec int
comparer string
- journalNum uint64
- prevJournalNum uint64
- nextFileNum uint64
+ journalNum int64
+ prevJournalNum int64
+ nextFileNum int64
seqNum uint64
compPtrs []cpRecord
addedTables []atRecord
@@ -77,17 +76,17 @@ func (p *sessionRecord) setComparer(name string) {
p.comparer = name
}
-func (p *sessionRecord) setJournalNum(num uint64) {
+func (p *sessionRecord) setJournalNum(num int64) {
p.hasRec |= 1 << recJournalNum
p.journalNum = num
}
-func (p *sessionRecord) setPrevJournalNum(num uint64) {
+func (p *sessionRecord) setPrevJournalNum(num int64) {
p.hasRec |= 1 << recPrevJournalNum
p.prevJournalNum = num
}
-func (p *sessionRecord) setNextFileNum(num uint64) {
+func (p *sessionRecord) setNextFileNum(num int64) {
p.hasRec |= 1 << recNextFileNum
p.nextFileNum = num
}
@@ -107,13 +106,13 @@ func (p *sessionRecord) resetCompPtrs() {
p.compPtrs = p.compPtrs[:0]
}
-func (p *sessionRecord) addTable(level int, num, size uint64, imin, imax iKey) {
+func (p *sessionRecord) addTable(level int, num, size int64, imin, imax iKey) {
p.hasRec |= 1 << recAddTable
p.addedTables = append(p.addedTables, atRecord{level, num, size, imin, imax})
}
func (p *sessionRecord) addTableFile(level int, t *tFile) {
- p.addTable(level, t.file.Num(), t.size, t.imin, t.imax)
+ p.addTable(level, t.fd.Num, t.size, t.imin, t.imax)
}
func (p *sessionRecord) resetAddedTables() {
@@ -121,7 +120,7 @@ func (p *sessionRecord) resetAddedTables() {
p.addedTables = p.addedTables[:0]
}
-func (p *sessionRecord) delTable(level int, num uint64) {
+func (p *sessionRecord) delTable(level int, num int64) {
p.hasRec |= 1 << recDelTable
p.deletedTables = append(p.deletedTables, dtRecord{level, num})
}
@@ -139,6 +138,13 @@ func (p *sessionRecord) putUvarint(w io.Writer, x uint64) {
_, p.err = w.Write(p.scratch[:n])
}
+func (p *sessionRecord) putVarint(w io.Writer, x int64) {
+ if x < 0 {
+ panic("invalid negative value")
+ }
+ p.putUvarint(w, uint64(x))
+}
+
func (p *sessionRecord) putBytes(w io.Writer, x []byte) {
if p.err != nil {
return
@@ -158,11 +164,11 @@ func (p *sessionRecord) encode(w io.Writer) error {
}
if p.has(recJournalNum) {
p.putUvarint(w, recJournalNum)
- p.putUvarint(w, p.journalNum)
+ p.putVarint(w, p.journalNum)
}
if p.has(recNextFileNum) {
p.putUvarint(w, recNextFileNum)
- p.putUvarint(w, p.nextFileNum)
+ p.putVarint(w, p.nextFileNum)
}
if p.has(recSeqNum) {
p.putUvarint(w, recSeqNum)
@@ -176,13 +182,13 @@ func (p *sessionRecord) encode(w io.Writer) error {
for _, r := range p.deletedTables {
p.putUvarint(w, recDelTable)
p.putUvarint(w, uint64(r.level))
- p.putUvarint(w, r.num)
+ p.putVarint(w, r.num)
}
for _, r := range p.addedTables {
p.putUvarint(w, recAddTable)
p.putUvarint(w, uint64(r.level))
- p.putUvarint(w, r.num)
- p.putUvarint(w, r.size)
+ p.putVarint(w, r.num)
+ p.putVarint(w, r.size)
p.putBytes(w, r.imin)
p.putBytes(w, r.imax)
}
@@ -196,9 +202,9 @@ func (p *sessionRecord) readUvarintMayEOF(field string, r io.ByteReader, mayEOF
x, err := binary.ReadUvarint(r)
if err != nil {
if err == io.ErrUnexpectedEOF || (mayEOF == false && err == io.EOF) {
- p.err = errors.NewErrCorrupted(nil, &ErrManifestCorrupted{field, "short read"})
+ p.err = errors.NewErrCorrupted(storage.FileDesc{}, &ErrManifestCorrupted{field, "short read"})
} else if strings.HasPrefix(err.Error(), "binary:") {
- p.err = errors.NewErrCorrupted(nil, &ErrManifestCorrupted{field, err.Error()})
+ p.err = errors.NewErrCorrupted(storage.FileDesc{}, &ErrManifestCorrupted{field, err.Error()})
} else {
p.err = err
}
@@ -211,6 +217,14 @@ func (p *sessionRecord) readUvarint(field string, r io.ByteReader) uint64 {
return p.readUvarintMayEOF(field, r, false)
}
+func (p *sessionRecord) readVarint(field string, r io.ByteReader) int64 {
+ x := int64(p.readUvarintMayEOF(field, r, false))
+ if x < 0 {
+ p.err = errors.NewErrCorrupted(storage.FileDesc{}, &ErrManifestCorrupted{field, "invalid negative value"})
+ }
+ return x
+}
+
func (p *sessionRecord) readBytes(field string, r byteReader) []byte {
if p.err != nil {
return nil
@@ -223,7 +237,7 @@ func (p *sessionRecord) readBytes(field string, r byteReader) []byte {
_, p.err = io.ReadFull(r, x)
if p.err != nil {
if p.err == io.ErrUnexpectedEOF {
- p.err = errors.NewErrCorrupted(nil, &ErrManifestCorrupted{field, "short read"})
+ p.err = errors.NewErrCorrupted(storage.FileDesc{}, &ErrManifestCorrupted{field, "short read"})
}
return nil
}
@@ -238,10 +252,6 @@ func (p *sessionRecord) readLevel(field string, r io.ByteReader) int {
if p.err != nil {
return 0
}
- if x >= uint64(p.numLevel) {
- p.err = errors.NewErrCorrupted(nil, &ErrManifestCorrupted{field, "invalid level number"})
- return 0
- }
return int(x)
}
@@ -266,17 +276,17 @@ func (p *sessionRecord) decode(r io.Reader) error {
p.setComparer(string(x))
}
case recJournalNum:
- x := p.readUvarint("journal-num", br)
+ x := p.readVarint("journal-num", br)
if p.err == nil {
p.setJournalNum(x)
}
case recPrevJournalNum:
- x := p.readUvarint("prev-journal-num", br)
+ x := p.readVarint("prev-journal-num", br)
if p.err == nil {
p.setPrevJournalNum(x)
}
case recNextFileNum:
- x := p.readUvarint("next-file-num", br)
+ x := p.readVarint("next-file-num", br)
if p.err == nil {
p.setNextFileNum(x)
}
@@ -293,8 +303,8 @@ func (p *sessionRecord) decode(r io.Reader) error {
}
case recAddTable:
level := p.readLevel("add-table.level", br)
- num := p.readUvarint("add-table.num", br)
- size := p.readUvarint("add-table.size", br)
+ num := p.readVarint("add-table.num", br)
+ size := p.readVarint("add-table.size", br)
imin := p.readBytes("add-table.imin", br)
imax := p.readBytes("add-table.imax", br)
if p.err == nil {
@@ -302,7 +312,7 @@ func (p *sessionRecord) decode(r io.Reader) error {
}
case recDelTable:
level := p.readLevel("del-table.level", br)
- num := p.readUvarint("del-table.num", br)
+ num := p.readVarint("del-table.num", br)
if p.err == nil {
p.delTable(level, num)
}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_record_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_record_test.go
deleted file mode 100644
index c0c035ae3..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_record_test.go
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
-// All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package leveldb
-
-import (
- "bytes"
- "testing"
-
- "github.com/syndtr/goleveldb/leveldb/opt"
-)
-
-func decodeEncode(v *sessionRecord) (res bool, err error) {
- b := new(bytes.Buffer)
- err = v.encode(b)
- if err != nil {
- return
- }
- v2 := &sessionRecord{numLevel: opt.DefaultNumLevel}
- err = v.decode(b)
- if err != nil {
- return
- }
- b2 := new(bytes.Buffer)
- err = v2.encode(b2)
- if err != nil {
- return
- }
- return bytes.Equal(b.Bytes(), b2.Bytes()), nil
-}
-
-func TestSessionRecord_EncodeDecode(t *testing.T) {
- big := uint64(1) << 50
- v := &sessionRecord{numLevel: opt.DefaultNumLevel}
- i := uint64(0)
- test := func() {
- res, err := decodeEncode(v)
- if err != nil {
- t.Fatalf("error when testing encode/decode sessionRecord: %v", err)
- }
- if !res {
- t.Error("encode/decode test failed at iteration:", i)
- }
- }
-
- for ; i < 4; i++ {
- test()
- v.addTable(3, big+300+i, big+400+i,
- newIkey([]byte("foo"), big+500+1, ktVal),
- newIkey([]byte("zoo"), big+600+1, ktDel))
- v.delTable(4, big+700+i)
- v.addCompPtr(int(i), newIkey([]byte("x"), big+900+1, ktVal))
- }
-
- v.setComparer("foo")
- v.setJournalNum(big + 100)
- v.setPrevJournalNum(big + 99)
- v.setNextFileNum(big + 200)
- v.setSeqNum(big + 1000)
- test()
-}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_util.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_util.go
index 007c02cde..e4fa98d92 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_util.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/session_util.go
@@ -17,15 +17,15 @@ import (
// Logging.
type dropper struct {
- s *session
- file storage.File
+ s *session
+ fd storage.FileDesc
}
func (d dropper) Drop(err error) {
if e, ok := err.(*journal.ErrCorrupted); ok {
- d.s.logf("journal@drop %s-%d S·%s %q", d.file.Type(), d.file.Num(), shortenb(e.Size), e.Reason)
+ d.s.logf("journal@drop %s-%d S·%s %q", d.fd.Type, d.fd.Num, shortenb(e.Size), e.Reason)
} else {
- d.s.logf("journal@drop %s-%d %q", d.file.Type(), d.file.Num(), err)
+ d.s.logf("journal@drop %s-%d %q", d.fd.Type, d.fd.Num, err)
}
}
@@ -34,25 +34,9 @@ func (s *session) logf(format string, v ...interface{}) { s.stor.Log(fmt.Sprintf
// File utils.
-func (s *session) getJournalFile(num uint64) storage.File {
- return s.stor.GetFile(num, storage.TypeJournal)
-}
-
-func (s *session) getTableFile(num uint64) storage.File {
- return s.stor.GetFile(num, storage.TypeTable)
-}
-
-func (s *session) getFiles(t storage.FileType) ([]storage.File, error) {
- return s.stor.GetFiles(t)
-}
-
-func (s *session) newTemp() storage.File {
- num := atomic.AddUint64(&s.stTempFileNum, 1) - 1
- return s.stor.GetFile(num, storage.TypeTemp)
-}
-
-func (s *session) tableFileFromRecord(r atRecord) *tFile {
- return newTableFile(s.getTableFile(r.num), r.size, r.imin, r.imax)
+func (s *session) newTemp() storage.FileDesc {
+ num := atomic.AddInt64(&s.stTempFileNum, 1) - 1
+ return storage.FileDesc{storage.TypeTemp, num}
}
// Session state.
@@ -80,47 +64,65 @@ func (s *session) setVersion(v *version) {
}
// Get current unused file number.
-func (s *session) nextFileNum() uint64 {
- return atomic.LoadUint64(&s.stNextFileNum)
+func (s *session) nextFileNum() int64 {
+ return atomic.LoadInt64(&s.stNextFileNum)
}
// Set current unused file number to num.
-func (s *session) setNextFileNum(num uint64) {
- atomic.StoreUint64(&s.stNextFileNum, num)
+func (s *session) setNextFileNum(num int64) {
+ atomic.StoreInt64(&s.stNextFileNum, num)
}
// Mark file number as used.
-func (s *session) markFileNum(num uint64) {
+func (s *session) markFileNum(num int64) {
nextFileNum := num + 1
for {
old, x := s.stNextFileNum, nextFileNum
if old > x {
x = old
}
- if atomic.CompareAndSwapUint64(&s.stNextFileNum, old, x) {
+ if atomic.CompareAndSwapInt64(&s.stNextFileNum, old, x) {
break
}
}
}
// Allocate a file number.
-func (s *session) allocFileNum() uint64 {
- return atomic.AddUint64(&s.stNextFileNum, 1) - 1
+func (s *session) allocFileNum() int64 {
+ return atomic.AddInt64(&s.stNextFileNum, 1) - 1
}
// Reuse given file number.
-func (s *session) reuseFileNum(num uint64) {
+func (s *session) reuseFileNum(num int64) {
for {
old, x := s.stNextFileNum, num
if old != x+1 {
x = old
}
- if atomic.CompareAndSwapUint64(&s.stNextFileNum, old, x) {
+ if atomic.CompareAndSwapInt64(&s.stNextFileNum, old, x) {
break
}
}
}
+// Set compaction ptr at given level; need external synchronization.
+func (s *session) setCompPtr(level int, ik iKey) {
+ if level >= len(s.stCompPtrs) {
+ newCompPtrs := make([]iKey, level+1)
+ copy(newCompPtrs, s.stCompPtrs)
+ s.stCompPtrs = newCompPtrs
+ }
+ s.stCompPtrs[level] = append(iKey{}, ik...)
+}
+
+// Get compaction ptr at given level; need external synchronization.
+func (s *session) getCompPtr(level int) iKey {
+ if level >= len(s.stCompPtrs) {
+ return nil
+ }
+ return s.stCompPtrs[level]
+}
+
// Manifest related utils.
// Fill given session record obj with current states; need external
@@ -149,29 +151,28 @@ func (s *session) fillRecord(r *sessionRecord, snapshot bool) {
// Mark if record has been committed, this will update session state;
// need external synchronization.
-func (s *session) recordCommited(r *sessionRecord) {
- if r.has(recJournalNum) {
- s.stJournalNum = r.journalNum
+func (s *session) recordCommited(rec *sessionRecord) {
+ if rec.has(recJournalNum) {
+ s.stJournalNum = rec.journalNum
}
- if r.has(recPrevJournalNum) {
- s.stPrevJournalNum = r.prevJournalNum
+ if rec.has(recPrevJournalNum) {
+ s.stPrevJournalNum = rec.prevJournalNum
}
- if r.has(recSeqNum) {
- s.stSeqNum = r.seqNum
+ if rec.has(recSeqNum) {
+ s.stSeqNum = rec.seqNum
}
- for _, p := range r.compPtrs {
- s.stCompPtrs[p.level] = iKey(p.ikey)
+ for _, r := range rec.compPtrs {
+ s.setCompPtr(r.level, iKey(r.ikey))
}
}
// Create a new manifest file; need external synchronization.
func (s *session) newManifest(rec *sessionRecord, v *version) (err error) {
- num := s.allocFileNum()
- file := s.stor.GetFile(num, storage.TypeManifest)
- writer, err := file.Create()
+ fd := storage.FileDesc{storage.TypeManifest, s.allocFileNum()}
+ writer, err := s.stor.Create(fd)
if err != nil {
return
}
@@ -182,7 +183,7 @@ func (s *session) newManifest(rec *sessionRecord, v *version) (err error) {
defer v.release()
}
if rec == nil {
- rec = &sessionRecord{numLevel: s.o.GetNumLevel()}
+ rec = &sessionRecord{}
}
s.fillRecord(rec, true)
v.fillRecord(rec)
@@ -196,16 +197,16 @@ func (s *session) newManifest(rec *sessionRecord, v *version) (err error) {
if s.manifestWriter != nil {
s.manifestWriter.Close()
}
- if s.manifestFile != nil {
- s.manifestFile.Remove()
+ if !s.manifestFd.Nil() {
+ s.stor.Remove(s.manifestFd)
}
- s.manifestFile = file
+ s.manifestFd = fd
s.manifestWriter = writer
s.manifest = jw
} else {
writer.Close()
- file.Remove()
- s.reuseFileNum(num)
+ s.stor.Remove(fd)
+ s.reuseFileNum(fd.Num)
}
}()
@@ -221,7 +222,7 @@ func (s *session) newManifest(rec *sessionRecord, v *version) (err error) {
if err != nil {
return
}
- err = s.stor.SetManifest(file)
+ err = s.stor.SetMeta(fd)
return
}
@@ -240,9 +241,11 @@ func (s *session) flushManifest(rec *sessionRecord) (err error) {
if err != nil {
return
}
- err = s.manifestWriter.Sync()
- if err != nil {
- return
+ if !s.o.GetNoSync() {
+ err = s.manifestWriter.Sync()
+ if err != nil {
+ return
+ }
}
s.recordCommited(rec)
return
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage.go
index 46cc9d070..cbe1dc103 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage.go
@@ -17,11 +17,12 @@ import (
"strings"
"sync"
"time"
-
- "github.com/syndtr/goleveldb/leveldb/util"
)
-var errFileOpen = errors.New("leveldb/storage: file still open")
+var (
+ errFileOpen = errors.New("leveldb/storage: file still open")
+ errReadOnly = errors.New("leveldb/storage: storage is read-only")
+)
type fileLock interface {
release() error
@@ -32,40 +33,52 @@ type fileStorageLock struct {
}
func (lock *fileStorageLock) Release() {
- fs := lock.fs
- fs.mu.Lock()
- defer fs.mu.Unlock()
- if fs.slock == lock {
- fs.slock = nil
+ if lock.fs != nil {
+ lock.fs.mu.Lock()
+ defer lock.fs.mu.Unlock()
+ if lock.fs.slock == lock {
+ lock.fs.slock = nil
+ }
}
- return
}
+const logSizeThreshold = 1024 * 1024 // 1 MiB
+
// fileStorage is a file-system backed storage.
type fileStorage struct {
- path string
-
- mu sync.Mutex
- flock fileLock
- slock *fileStorageLock
- logw *os.File
- buf []byte
+ path string
+ readOnly bool
+
+ mu sync.Mutex
+ flock fileLock
+ slock *fileStorageLock
+ logw *os.File
+ logSize int64
+ buf []byte
// Opened file counter; if open < 0 means closed.
open int
day int
}
// OpenFile returns a new filesytem-backed storage implementation with the given
-// path. This also hold a file lock, so any subsequent attempt to open the same
-// path will fail.
+// path. This also acquire a file lock, so any subsequent attempt to open the
+// same path will fail.
//
// The storage must be closed after use, by calling Close method.
-func OpenFile(path string) (Storage, error) {
- if err := os.MkdirAll(path, 0755); err != nil {
+func OpenFile(path string, readOnly bool) (Storage, error) {
+ if fi, err := os.Stat(path); err == nil {
+ if !fi.IsDir() {
+ return nil, fmt.Errorf("leveldb/storage: open %s: not a directory", path)
+ }
+ } else if os.IsNotExist(err) && !readOnly {
+ if err := os.MkdirAll(path, 0755); err != nil {
+ return nil, err
+ }
+ } else {
return nil, err
}
- flock, err := newFileLock(filepath.Join(path, "LOCK"))
+ flock, err := newFileLock(filepath.Join(path, "LOCK"), readOnly)
if err != nil {
return nil, err
}
@@ -76,23 +89,42 @@ func OpenFile(path string) (Storage, error) {
}
}()
- rename(filepath.Join(path, "LOG"), filepath.Join(path, "LOG.old"))
- logw, err := os.OpenFile(filepath.Join(path, "LOG"), os.O_WRONLY|os.O_CREATE, 0644)
- if err != nil {
- return nil, err
+ var (
+ logw *os.File
+ logSize int64
+ )
+ if !readOnly {
+ logw, err = os.OpenFile(filepath.Join(path, "LOG"), os.O_WRONLY|os.O_CREATE, 0644)
+ if err != nil {
+ return nil, err
+ }
+ logSize, err = logw.Seek(0, os.SEEK_END)
+ if err != nil {
+ logw.Close()
+ return nil, err
+ }
}
- fs := &fileStorage{path: path, flock: flock, logw: logw}
+ fs := &fileStorage{
+ path: path,
+ readOnly: readOnly,
+ flock: flock,
+ logw: logw,
+ logSize: logSize,
+ }
runtime.SetFinalizer(fs, (*fileStorage).Close)
return fs, nil
}
-func (fs *fileStorage) Lock() (util.Releaser, error) {
+func (fs *fileStorage) Lock() (Lock, error) {
fs.mu.Lock()
defer fs.mu.Unlock()
if fs.open < 0 {
return nil, ErrClosed
}
+ if fs.readOnly {
+ return &fileStorageLock{}, nil
+ }
if fs.slock != nil {
return nil, ErrLocked
}
@@ -101,7 +133,7 @@ func (fs *fileStorage) Lock() (util.Releaser, error) {
}
func itoa(buf []byte, i int, wid int) []byte {
- var u uint = uint(i)
+ u := uint(i)
if u == 0 && wid <= 1 {
return append(buf, '0')
}
@@ -126,6 +158,22 @@ func (fs *fileStorage) printDay(t time.Time) {
}
func (fs *fileStorage) doLog(t time.Time, str string) {
+ if fs.logSize > logSizeThreshold {
+ // Rotate log file.
+ fs.logw.Close()
+ fs.logw = nil
+ fs.logSize = 0
+ rename(filepath.Join(fs.path, "LOG"), filepath.Join(fs.path, "LOG.old"))
+ }
+ if fs.logw == nil {
+ var err error
+ fs.logw, err = os.OpenFile(filepath.Join(fs.path, "LOG"), os.O_WRONLY|os.O_CREATE, 0644)
+ if err != nil {
+ return
+ }
+ // Force printDay on new log file.
+ fs.day = 0
+ }
fs.printDay(t)
hour, min, sec := t.Clock()
msec := t.Nanosecond() / 1e3
@@ -145,65 +193,71 @@ func (fs *fileStorage) doLog(t time.Time, str string) {
}
func (fs *fileStorage) Log(str string) {
- t := time.Now()
- fs.mu.Lock()
- defer fs.mu.Unlock()
- if fs.open < 0 {
- return
+ if !fs.readOnly {
+ t := time.Now()
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ if fs.open < 0 {
+ return
+ }
+ fs.doLog(t, str)
}
- fs.doLog(t, str)
}
func (fs *fileStorage) log(str string) {
- fs.doLog(time.Now(), str)
+ if !fs.readOnly {
+ fs.doLog(time.Now(), str)
+ }
}
-func (fs *fileStorage) GetFile(num uint64, t FileType) File {
- return &file{fs: fs, num: num, t: t}
-}
+func (fs *fileStorage) SetMeta(fd FileDesc) (err error) {
+ if !FileDescOk(fd) {
+ return ErrInvalidFile
+ }
+ if fs.readOnly {
+ return errReadOnly
+ }
-func (fs *fileStorage) GetFiles(t FileType) (ff []File, err error) {
fs.mu.Lock()
defer fs.mu.Unlock()
if fs.open < 0 {
- return nil, ErrClosed
+ return ErrClosed
}
- dir, err := os.Open(fs.path)
+ defer func() {
+ if err != nil {
+ fs.log(fmt.Sprintf("CURRENT: %v", err))
+ }
+ }()
+ path := fmt.Sprintf("%s.%d", filepath.Join(fs.path, "CURRENT"), fd.Num)
+ w, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return
}
- fnn, err := dir.Readdirnames(0)
- // Close the dir first before checking for Readdirnames error.
- if err := dir.Close(); err != nil {
- fs.log(fmt.Sprintf("close dir: %v", err))
+ _, err = fmt.Fprintln(w, fsGenName(fd))
+ // Close the file first.
+ if cerr := w.Close(); cerr != nil {
+ fs.log(fmt.Sprintf("close CURRENT.%d: %v", fd.Num, cerr))
}
if err != nil {
return
}
- f := &file{fs: fs}
- for _, fn := range fnn {
- if f.parse(fn) && (f.t&t) != 0 {
- ff = append(ff, f)
- f = &file{fs: fs}
- }
- }
- return
+ return rename(path, filepath.Join(fs.path, "CURRENT"))
}
-func (fs *fileStorage) GetManifest() (f File, err error) {
+func (fs *fileStorage) GetMeta() (fd FileDesc, err error) {
fs.mu.Lock()
defer fs.mu.Unlock()
if fs.open < 0 {
- return nil, ErrClosed
+ return FileDesc{}, ErrClosed
}
dir, err := os.Open(fs.path)
if err != nil {
return
}
- fnn, err := dir.Readdirnames(0)
+ names, err := dir.Readdirnames(0)
// Close the dir first before checking for Readdirnames error.
- if err := dir.Close(); err != nil {
- fs.log(fmt.Sprintf("close dir: %v", err))
+ if ce := dir.Close(); ce != nil {
+ fs.log(fmt.Sprintf("close dir: %v", ce))
}
if err != nil {
return
@@ -212,55 +266,64 @@ func (fs *fileStorage) GetManifest() (f File, err error) {
var rem []string
var pend bool
var cerr error
- for _, fn := range fnn {
- if strings.HasPrefix(fn, "CURRENT") {
- pend1 := len(fn) > 7
+ for _, name := range names {
+ if strings.HasPrefix(name, "CURRENT") {
+ pend1 := len(name) > 7
+ var pendNum int64
// Make sure it is valid name for a CURRENT file, otherwise skip it.
if pend1 {
- if fn[7] != '.' || len(fn) < 9 {
- fs.log(fmt.Sprintf("skipping %s: invalid file name", fn))
+ if name[7] != '.' || len(name) < 9 {
+ fs.log(fmt.Sprintf("skipping %s: invalid file name", name))
continue
}
- if _, e1 := strconv.ParseUint(fn[8:], 10, 0); e1 != nil {
- fs.log(fmt.Sprintf("skipping %s: invalid file num: %v", fn, e1))
+ var e1 error
+ if pendNum, e1 = strconv.ParseInt(name[8:], 10, 0); e1 != nil {
+ fs.log(fmt.Sprintf("skipping %s: invalid file num: %v", name, e1))
continue
}
}
- path := filepath.Join(fs.path, fn)
+ path := filepath.Join(fs.path, name)
r, e1 := os.OpenFile(path, os.O_RDONLY, 0)
if e1 != nil {
- return nil, e1
+ return FileDesc{}, e1
}
b, e1 := ioutil.ReadAll(r)
if e1 != nil {
r.Close()
- return nil, e1
+ return FileDesc{}, e1
}
- f1 := &file{fs: fs}
- if len(b) < 1 || b[len(b)-1] != '\n' || !f1.parse(string(b[:len(b)-1])) {
- fs.log(fmt.Sprintf("skipping %s: corrupted or incomplete", fn))
+ var fd1 FileDesc
+ if len(b) < 1 || b[len(b)-1] != '\n' || !fsParseNamePtr(string(b[:len(b)-1]), &fd1) {
+ fs.log(fmt.Sprintf("skipping %s: corrupted or incomplete", name))
if pend1 {
- rem = append(rem, fn)
+ rem = append(rem, name)
}
if !pend1 || cerr == nil {
- cerr = fmt.Errorf("leveldb/storage: corrupted or incomplete %s file", fn)
+ metaFd, _ := fsParseName(name)
+ cerr = &ErrCorrupted{
+ Fd: metaFd,
+ Err: errors.New("leveldb/storage: corrupted or incomplete meta file"),
+ }
}
- } else if f != nil && f1.Num() < f.Num() {
- fs.log(fmt.Sprintf("skipping %s: obsolete", fn))
+ } else if pend1 && pendNum != fd1.Num {
+ fs.log(fmt.Sprintf("skipping %s: inconsistent pending-file num: %d vs %d", name, pendNum, fd1.Num))
+ rem = append(rem, name)
+ } else if fd1.Num < fd.Num {
+ fs.log(fmt.Sprintf("skipping %s: obsolete", name))
if pend1 {
- rem = append(rem, fn)
+ rem = append(rem, name)
}
} else {
- f = f1
+ fd = fd1
pend = pend1
}
if err := r.Close(); err != nil {
- fs.log(fmt.Sprintf("close %s: %v", fn, err))
+ fs.log(fmt.Sprintf("close %s: %v", name, err))
}
}
}
// Don't remove any files if there is no valid CURRENT file.
- if f == nil {
+ if fd.Nil() {
if cerr != nil {
err = cerr
} else {
@@ -268,267 +331,253 @@ func (fs *fileStorage) GetManifest() (f File, err error) {
}
return
}
- // Rename pending CURRENT file to an effective CURRENT.
- if pend {
- path := fmt.Sprintf("%s.%d", filepath.Join(fs.path, "CURRENT"), f.Num())
- if err := rename(path, filepath.Join(fs.path, "CURRENT")); err != nil {
- fs.log(fmt.Sprintf("CURRENT.%d -> CURRENT: %v", f.Num(), err))
+ if !fs.readOnly {
+ // Rename pending CURRENT file to an effective CURRENT.
+ if pend {
+ path := fmt.Sprintf("%s.%d", filepath.Join(fs.path, "CURRENT"), fd.Num)
+ if err := rename(path, filepath.Join(fs.path, "CURRENT")); err != nil {
+ fs.log(fmt.Sprintf("CURRENT.%d -> CURRENT: %v", fd.Num, err))
+ }
}
- }
- // Remove obsolete or incomplete pending CURRENT files.
- for _, fn := range rem {
- path := filepath.Join(fs.path, fn)
- if err := os.Remove(path); err != nil {
- fs.log(fmt.Sprintf("remove %s: %v", fn, err))
+ // Remove obsolete or incomplete pending CURRENT files.
+ for _, name := range rem {
+ path := filepath.Join(fs.path, name)
+ if err := os.Remove(path); err != nil {
+ fs.log(fmt.Sprintf("remove %s: %v", name, err))
+ }
}
}
return
}
-func (fs *fileStorage) SetManifest(f File) (err error) {
+func (fs *fileStorage) List(ft FileType) (fds []FileDesc, err error) {
fs.mu.Lock()
defer fs.mu.Unlock()
if fs.open < 0 {
- return ErrClosed
- }
- f2, ok := f.(*file)
- if !ok || f2.t != TypeManifest {
- return ErrInvalidFile
+ return nil, ErrClosed
}
- defer func() {
- if err != nil {
- fs.log(fmt.Sprintf("CURRENT: %v", err))
- }
- }()
- path := fmt.Sprintf("%s.%d", filepath.Join(fs.path, "CURRENT"), f2.Num())
- w, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
+ dir, err := os.Open(fs.path)
if err != nil {
- return err
+ return
}
- _, err = fmt.Fprintln(w, f2.name())
- // Close the file first.
- if err := w.Close(); err != nil {
- fs.log(fmt.Sprintf("close CURRENT.%d: %v", f2.num, err))
+ names, err := dir.Readdirnames(0)
+ // Close the dir first before checking for Readdirnames error.
+ if cerr := dir.Close(); cerr != nil {
+ fs.log(fmt.Sprintf("close dir: %v", cerr))
}
- if err != nil {
- return err
+ if err == nil {
+ for _, name := range names {
+ if fd, ok := fsParseName(name); ok && fd.Type&ft != 0 {
+ fds = append(fds, fd)
+ }
+ }
}
- return rename(path, filepath.Join(fs.path, "CURRENT"))
+ return
}
-func (fs *fileStorage) Close() error {
+func (fs *fileStorage) Open(fd FileDesc) (Reader, error) {
+ if !FileDescOk(fd) {
+ return nil, ErrInvalidFile
+ }
+
fs.mu.Lock()
defer fs.mu.Unlock()
if fs.open < 0 {
- return ErrClosed
- }
- // Clear the finalizer.
- runtime.SetFinalizer(fs, nil)
-
- if fs.open > 0 {
- fs.log(fmt.Sprintf("refuse to close, %d files still open", fs.open))
- return fmt.Errorf("leveldb/storage: cannot close, %d files still open", fs.open)
+ return nil, ErrClosed
}
- fs.open = -1
- e1 := fs.logw.Close()
- err := fs.flock.release()
- if err == nil {
- err = e1
+ of, err := os.OpenFile(filepath.Join(fs.path, fsGenName(fd)), os.O_RDONLY, 0)
+ if err != nil {
+ if fsHasOldName(fd) && os.IsNotExist(err) {
+ of, err = os.OpenFile(filepath.Join(fs.path, fsGenOldName(fd)), os.O_RDONLY, 0)
+ if err == nil {
+ goto ok
+ }
+ }
+ return nil, err
}
- return err
-}
-
-type fileWrap struct {
- *os.File
- f *file
+ok:
+ fs.open++
+ return &fileWrap{File: of, fs: fs, fd: fd}, nil
}
-func (fw fileWrap) Sync() error {
- if err := fw.File.Sync(); err != nil {
- return err
+func (fs *fileStorage) Create(fd FileDesc) (Writer, error) {
+ if !FileDescOk(fd) {
+ return nil, ErrInvalidFile
}
- if fw.f.Type() == TypeManifest {
- // Also sync parent directory if file type is manifest.
- // See: https://code.google.com/p/leveldb/issues/detail?id=190.
- if err := syncDir(fw.f.fs.path); err != nil {
- return err
- }
+ if fs.readOnly {
+ return nil, errReadOnly
}
- return nil
-}
-func (fw fileWrap) Close() error {
- f := fw.f
- f.fs.mu.Lock()
- defer f.fs.mu.Unlock()
- if !f.open {
- return ErrClosed
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ if fs.open < 0 {
+ return nil, ErrClosed
}
- f.open = false
- f.fs.open--
- err := fw.File.Close()
+ of, err := os.OpenFile(filepath.Join(fs.path, fsGenName(fd)), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
- f.fs.log(fmt.Sprintf("close %s.%d: %v", f.Type(), f.Num(), err))
+ return nil, err
}
- return err
+ fs.open++
+ return &fileWrap{File: of, fs: fs, fd: fd}, nil
}
-type file struct {
- fs *fileStorage
- num uint64
- t FileType
- open bool
-}
-
-func (f *file) Open() (Reader, error) {
- f.fs.mu.Lock()
- defer f.fs.mu.Unlock()
- if f.fs.open < 0 {
- return nil, ErrClosed
+func (fs *fileStorage) Remove(fd FileDesc) error {
+ if !FileDescOk(fd) {
+ return ErrInvalidFile
}
- if f.open {
- return nil, errFileOpen
+ if fs.readOnly {
+ return errReadOnly
}
- of, err := os.OpenFile(f.path(), os.O_RDONLY, 0)
+
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ if fs.open < 0 {
+ return ErrClosed
+ }
+ err := os.Remove(filepath.Join(fs.path, fsGenName(fd)))
if err != nil {
- if f.hasOldName() && os.IsNotExist(err) {
- of, err = os.OpenFile(f.oldPath(), os.O_RDONLY, 0)
- if err == nil {
- goto ok
+ if fsHasOldName(fd) && os.IsNotExist(err) {
+ if e1 := os.Remove(filepath.Join(fs.path, fsGenOldName(fd))); !os.IsNotExist(e1) {
+ fs.log(fmt.Sprintf("remove %s: %v (old name)", fd, err))
+ err = e1
}
+ } else {
+ fs.log(fmt.Sprintf("remove %s: %v", fd, err))
}
- return nil, err
}
-ok:
- f.open = true
- f.fs.open++
- return fileWrap{of, f}, nil
+ return err
}
-func (f *file) Create() (Writer, error) {
- f.fs.mu.Lock()
- defer f.fs.mu.Unlock()
- if f.fs.open < 0 {
- return nil, ErrClosed
+func (fs *fileStorage) Rename(oldfd, newfd FileDesc) error {
+ if !FileDescOk(oldfd) || !FileDescOk(newfd) {
+ return ErrInvalidFile
}
- if f.open {
- return nil, errFileOpen
+ if oldfd == newfd {
+ return nil
}
- of, err := os.OpenFile(f.path(), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
- if err != nil {
- return nil, err
+ if fs.readOnly {
+ return errReadOnly
}
- f.open = true
- f.fs.open++
- return fileWrap{of, f}, nil
+
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ if fs.open < 0 {
+ return ErrClosed
+ }
+ return rename(filepath.Join(fs.path, fsGenName(oldfd)), filepath.Join(fs.path, fsGenName(newfd)))
}
-func (f *file) Replace(newfile File) error {
- f.fs.mu.Lock()
- defer f.fs.mu.Unlock()
- if f.fs.open < 0 {
+func (fs *fileStorage) Close() error {
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ if fs.open < 0 {
return ErrClosed
}
- newfile2, ok := newfile.(*file)
- if !ok {
- return ErrInvalidFile
+ // Clear the finalizer.
+ runtime.SetFinalizer(fs, nil)
+
+ if fs.open > 0 {
+ fs.log(fmt.Sprintf("close: warning, %d files still open", fs.open))
}
- if f.open || newfile2.open {
- return errFileOpen
+ fs.open = -1
+ if fs.logw != nil {
+ fs.logw.Close()
}
- return rename(newfile2.path(), f.path())
+ return fs.flock.release()
}
-func (f *file) Type() FileType {
- return f.t
+type fileWrap struct {
+ *os.File
+ fs *fileStorage
+ fd FileDesc
+ closed bool
}
-func (f *file) Num() uint64 {
- return f.num
+func (fw *fileWrap) Sync() error {
+ if err := fw.File.Sync(); err != nil {
+ return err
+ }
+ if fw.fd.Type == TypeManifest {
+ // Also sync parent directory if file type is manifest.
+ // See: https://code.google.com/p/leveldb/issues/detail?id=190.
+ if err := syncDir(fw.fs.path); err != nil {
+ fw.fs.log(fmt.Sprintf("syncDir: %v", err))
+ return err
+ }
+ }
+ return nil
}
-func (f *file) Remove() error {
- f.fs.mu.Lock()
- defer f.fs.mu.Unlock()
- if f.fs.open < 0 {
+func (fw *fileWrap) Close() error {
+ fw.fs.mu.Lock()
+ defer fw.fs.mu.Unlock()
+ if fw.closed {
return ErrClosed
}
- if f.open {
- return errFileOpen
- }
- err := os.Remove(f.path())
+ fw.closed = true
+ fw.fs.open--
+ err := fw.File.Close()
if err != nil {
- f.fs.log(fmt.Sprintf("remove %s.%d: %v", f.Type(), f.Num(), err))
- }
- // Also try remove file with old name, just in case.
- if f.hasOldName() {
- if e1 := os.Remove(f.oldPath()); !os.IsNotExist(e1) {
- f.fs.log(fmt.Sprintf("remove %s.%d: %v (old name)", f.Type(), f.Num(), err))
- err = e1
- }
+ fw.fs.log(fmt.Sprintf("close %s: %v", fw.fd, err))
}
return err
}
-func (f *file) hasOldName() bool {
- return f.t == TypeTable
-}
-
-func (f *file) oldName() string {
- switch f.t {
- case TypeTable:
- return fmt.Sprintf("%06d.sst", f.num)
- }
- return f.name()
-}
-
-func (f *file) oldPath() string {
- return filepath.Join(f.fs.path, f.oldName())
-}
-
-func (f *file) name() string {
- switch f.t {
+func fsGenName(fd FileDesc) string {
+ switch fd.Type {
case TypeManifest:
- return fmt.Sprintf("MANIFEST-%06d", f.num)
+ return fmt.Sprintf("MANIFEST-%06d", fd.Num)
case TypeJournal:
- return fmt.Sprintf("%06d.log", f.num)
+ return fmt.Sprintf("%06d.log", fd.Num)
case TypeTable:
- return fmt.Sprintf("%06d.ldb", f.num)
+ return fmt.Sprintf("%06d.ldb", fd.Num)
case TypeTemp:
- return fmt.Sprintf("%06d.tmp", f.num)
+ return fmt.Sprintf("%06d.tmp", fd.Num)
default:
panic("invalid file type")
}
}
-func (f *file) path() string {
- return filepath.Join(f.fs.path, f.name())
+func fsHasOldName(fd FileDesc) bool {
+ return fd.Type == TypeTable
}
-func (f *file) parse(name string) bool {
- var num uint64
+func fsGenOldName(fd FileDesc) string {
+ switch fd.Type {
+ case TypeTable:
+ return fmt.Sprintf("%06d.sst", fd.Num)
+ }
+ return fsGenName(fd)
+}
+
+func fsParseName(name string) (fd FileDesc, ok bool) {
var tail string
- _, err := fmt.Sscanf(name, "%d.%s", &num, &tail)
+ _, err := fmt.Sscanf(name, "%d.%s", &fd.Num, &tail)
if err == nil {
switch tail {
case "log":
- f.t = TypeJournal
+ fd.Type = TypeJournal
case "ldb", "sst":
- f.t = TypeTable
+ fd.Type = TypeTable
case "tmp":
- f.t = TypeTemp
+ fd.Type = TypeTemp
default:
- return false
+ return
}
- f.num = num
- return true
+ return fd, true
}
- n, _ := fmt.Sscanf(name, "MANIFEST-%d%s", &num, &tail)
+ n, _ := fmt.Sscanf(name, "MANIFEST-%d%s", &fd.Num, &tail)
if n == 1 {
- f.t = TypeManifest
- f.num = num
- return true
+ fd.Type = TypeManifest
+ return fd, true
}
+ return
+}
- return false
+func fsParseNamePtr(name string, fd *FileDesc) bool {
+ _fd, ok := fsParseName(name)
+ if fd != nil {
+ *fd = _fd
+ }
+ return ok
}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_plan9.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_plan9.go
index 42940d769..bab62bfce 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_plan9.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_plan9.go
@@ -19,8 +19,21 @@ func (fl *plan9FileLock) release() error {
return fl.f.Close()
}
-func newFileLock(path string) (fl fileLock, err error) {
- f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, os.ModeExclusive|0644)
+func newFileLock(path string, readOnly bool) (fl fileLock, err error) {
+ var (
+ flag int
+ perm os.FileMode
+ )
+ if readOnly {
+ flag = os.O_RDONLY
+ } else {
+ flag = os.O_RDWR
+ perm = os.ModeExclusive
+ }
+ f, err := os.OpenFile(path, flag, perm)
+ if os.IsNotExist(err) {
+ f, err = os.OpenFile(path, flag|os.O_CREATE, perm|0644)
+ }
if err != nil {
return
}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_solaris.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_solaris.go
index 102031bfd..79901ee4a 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_solaris.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_solaris.go
@@ -18,18 +18,27 @@ type unixFileLock struct {
}
func (fl *unixFileLock) release() error {
- if err := setFileLock(fl.f, false); err != nil {
+ if err := setFileLock(fl.f, false, false); err != nil {
return err
}
return fl.f.Close()
}
-func newFileLock(path string) (fl fileLock, err error) {
- f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0644)
+func newFileLock(path string, readOnly bool) (fl fileLock, err error) {
+ var flag int
+ if readOnly {
+ flag = os.O_RDONLY
+ } else {
+ flag = os.O_RDWR
+ }
+ f, err := os.OpenFile(path, flag, 0)
+ if os.IsNotExist(err) {
+ f, err = os.OpenFile(path, flag|os.O_CREATE, 0644)
+ }
if err != nil {
return
}
- err = setFileLock(f, true)
+ err = setFileLock(f, readOnly, true)
if err != nil {
f.Close()
return
@@ -38,7 +47,7 @@ func newFileLock(path string) (fl fileLock, err error) {
return
}
-func setFileLock(f *os.File, lock bool) error {
+func setFileLock(f *os.File, readOnly, lock bool) error {
flock := syscall.Flock_t{
Type: syscall.F_UNLCK,
Start: 0,
@@ -46,7 +55,11 @@ func setFileLock(f *os.File, lock bool) error {
Whence: 1,
}
if lock {
- flock.Type = syscall.F_WRLCK
+ if readOnly {
+ flock.Type = syscall.F_RDLCK
+ } else {
+ flock.Type = syscall.F_WRLCK
+ }
}
return syscall.FcntlFlock(f.Fd(), syscall.F_SETLK, &flock)
}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_test.go
deleted file mode 100644
index 92abcbb7d..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_test.go
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
-// All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package storage
-
-import (
- "fmt"
- "os"
- "path/filepath"
- "testing"
-)
-
-var cases = []struct {
- oldName []string
- name string
- ftype FileType
- num uint64
-}{
- {nil, "000100.log", TypeJournal, 100},
- {nil, "000000.log", TypeJournal, 0},
- {[]string{"000000.sst"}, "000000.ldb", TypeTable, 0},
- {nil, "MANIFEST-000002", TypeManifest, 2},
- {nil, "MANIFEST-000007", TypeManifest, 7},
- {nil, "18446744073709551615.log", TypeJournal, 18446744073709551615},
- {nil, "000100.tmp", TypeTemp, 100},
-}
-
-var invalidCases = []string{
- "",
- "foo",
- "foo-dx-100.log",
- ".log",
- "",
- "manifest",
- "CURREN",
- "CURRENTX",
- "MANIFES",
- "MANIFEST",
- "MANIFEST-",
- "XMANIFEST-3",
- "MANIFEST-3x",
- "LOC",
- "LOCKx",
- "LO",
- "LOGx",
- "18446744073709551616.log",
- "184467440737095516150.log",
- "100",
- "100.",
- "100.lop",
-}
-
-func TestFileStorage_CreateFileName(t *testing.T) {
- for _, c := range cases {
- f := &file{num: c.num, t: c.ftype}
- if f.name() != c.name {
- t.Errorf("invalid filename got '%s', want '%s'", f.name(), c.name)
- }
- }
-}
-
-func TestFileStorage_ParseFileName(t *testing.T) {
- for _, c := range cases {
- for _, name := range append([]string{c.name}, c.oldName...) {
- f := new(file)
- if !f.parse(name) {
- t.Errorf("cannot parse filename '%s'", name)
- continue
- }
- if f.Type() != c.ftype {
- t.Errorf("filename '%s' invalid type got '%d', want '%d'", name, f.Type(), c.ftype)
- }
- if f.Num() != c.num {
- t.Errorf("filename '%s' invalid number got '%d', want '%d'", name, f.Num(), c.num)
- }
- }
- }
-}
-
-func TestFileStorage_InvalidFileName(t *testing.T) {
- for _, name := range invalidCases {
- f := new(file)
- if f.parse(name) {
- t.Errorf("filename '%s' should be invalid", name)
- }
- }
-}
-
-func TestFileStorage_Locking(t *testing.T) {
- path := filepath.Join(os.TempDir(), fmt.Sprintf("goleveldbtestfd-%d", os.Getuid()))
-
- _, err := os.Stat(path)
- if err == nil {
- err = os.RemoveAll(path)
- if err != nil {
- t.Fatal("RemoveAll: got error: ", err)
- }
- }
-
- p1, err := OpenFile(path)
- if err != nil {
- t.Fatal("OpenFile(1): got error: ", err)
- }
-
- defer os.RemoveAll(path)
-
- p2, err := OpenFile(path)
- if err != nil {
- t.Logf("OpenFile(2): got error: %s (expected)", err)
- } else {
- p2.Close()
- p1.Close()
- t.Fatal("OpenFile(2): expect error")
- }
-
- p1.Close()
-
- p3, err := OpenFile(path)
- if err != nil {
- t.Fatal("OpenFile(3): got error: ", err)
- }
- defer p3.Close()
-
- l, err := p3.Lock()
- if err != nil {
- t.Fatal("storage lock failed(1): ", err)
- }
- _, err = p3.Lock()
- if err == nil {
- t.Fatal("expect error for second storage lock attempt")
- } else {
- t.Logf("storage lock got error: %s (expected)", err)
- }
- l.Release()
- _, err = p3.Lock()
- if err != nil {
- t.Fatal("storage lock failed(2): ", err)
- }
-}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_unix.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_unix.go
index d0a604b7a..7e2991537 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_unix.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_unix.go
@@ -18,18 +18,27 @@ type unixFileLock struct {
}
func (fl *unixFileLock) release() error {
- if err := setFileLock(fl.f, false); err != nil {
+ if err := setFileLock(fl.f, false, false); err != nil {
return err
}
return fl.f.Close()
}
-func newFileLock(path string) (fl fileLock, err error) {
- f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0644)
+func newFileLock(path string, readOnly bool) (fl fileLock, err error) {
+ var flag int
+ if readOnly {
+ flag = os.O_RDONLY
+ } else {
+ flag = os.O_RDWR
+ }
+ f, err := os.OpenFile(path, flag, 0)
+ if os.IsNotExist(err) {
+ f, err = os.OpenFile(path, flag|os.O_CREATE, 0644)
+ }
if err != nil {
return
}
- err = setFileLock(f, true)
+ err = setFileLock(f, readOnly, true)
if err != nil {
f.Close()
return
@@ -38,10 +47,14 @@ func newFileLock(path string) (fl fileLock, err error) {
return
}
-func setFileLock(f *os.File, lock bool) error {
+func setFileLock(f *os.File, readOnly, lock bool) error {
how := syscall.LOCK_UN
if lock {
- how = syscall.LOCK_EX
+ if readOnly {
+ how = syscall.LOCK_SH
+ } else {
+ how = syscall.LOCK_EX
+ }
}
return syscall.Flock(int(f.Fd()), how|syscall.LOCK_NB)
}
@@ -50,13 +63,23 @@ func rename(oldpath, newpath string) error {
return os.Rename(oldpath, newpath)
}
+func isErrInvalid(err error) bool {
+ if err == os.ErrInvalid {
+ return true
+ }
+ if syserr, ok := err.(*os.SyscallError); ok && syserr.Err == syscall.EINVAL {
+ return true
+ }
+ return false
+}
+
func syncDir(name string) error {
f, err := os.Open(name)
if err != nil {
return err
}
defer f.Close()
- if err := f.Sync(); err != nil {
+ if err := f.Sync(); err != nil && !isErrInvalid(err) {
return err
}
return nil
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_windows.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_windows.go
index 50c3c454e..899335fd7 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_windows.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_windows.go
@@ -29,12 +29,22 @@ func (fl *windowsFileLock) release() error {
return syscall.Close(fl.fd)
}
-func newFileLock(path string) (fl fileLock, err error) {
+func newFileLock(path string, readOnly bool) (fl fileLock, err error) {
pathp, err := syscall.UTF16PtrFromString(path)
if err != nil {
return
}
- fd, err := syscall.CreateFile(pathp, syscall.GENERIC_READ|syscall.GENERIC_WRITE, 0, nil, syscall.CREATE_ALWAYS, syscall.FILE_ATTRIBUTE_NORMAL, 0)
+ var access, shareMode uint32
+ if readOnly {
+ access = syscall.GENERIC_READ
+ shareMode = syscall.FILE_SHARE_READ
+ } else {
+ access = syscall.GENERIC_READ | syscall.GENERIC_WRITE
+ }
+ fd, err := syscall.CreateFile(pathp, access, shareMode, nil, syscall.OPEN_EXISTING, syscall.FILE_ATTRIBUTE_NORMAL, 0)
+ if err == syscall.ERROR_FILE_NOT_FOUND {
+ fd, err = syscall.CreateFile(pathp, access, shareMode, nil, syscall.OPEN_ALWAYS, syscall.FILE_ATTRIBUTE_NORMAL, 0)
+ }
if err != nil {
return
}
@@ -47,9 +57,8 @@ func moveFileEx(from *uint16, to *uint16, flags uint32) error {
if r1 == 0 {
if e1 != 0 {
return error(e1)
- } else {
- return syscall.EINVAL
}
+ return syscall.EINVAL
}
return nil
}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/mem_storage.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/mem_storage.go
index fc1c8165d..9b70e1513 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/mem_storage.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/mem_storage.go
@@ -10,8 +10,6 @@ import (
"bytes"
"os"
"sync"
-
- "github.com/syndtr/goleveldb/leveldb/util"
)
const typeShift = 3
@@ -32,10 +30,10 @@ func (lock *memStorageLock) Release() {
// memStorage is a memory-backed storage.
type memStorage struct {
- mu sync.Mutex
- slock *memStorageLock
- files map[uint64]*memFile
- manifest *memFilePtr
+ mu sync.Mutex
+ slock *memStorageLock
+ files map[uint64]*memFile
+ meta FileDesc
}
// NewMemStorage returns a new memory-backed storage implementation.
@@ -45,7 +43,7 @@ func NewMemStorage() Storage {
}
}
-func (ms *memStorage) Lock() (util.Releaser, error) {
+func (ms *memStorage) Lock() (Lock, error) {
ms.mu.Lock()
defer ms.mu.Unlock()
if ms.slock != nil {
@@ -57,147 +55,164 @@ func (ms *memStorage) Lock() (util.Releaser, error) {
func (*memStorage) Log(str string) {}
-func (ms *memStorage) GetFile(num uint64, t FileType) File {
- return &memFilePtr{ms: ms, num: num, t: t}
-}
+func (ms *memStorage) SetMeta(fd FileDesc) error {
+ if !FileDescOk(fd) {
+ return ErrInvalidFile
+ }
-func (ms *memStorage) GetFiles(t FileType) ([]File, error) {
ms.mu.Lock()
- var ff []File
- for x, _ := range ms.files {
- num, mt := x>>typeShift, FileType(x)&TypeAll
- if mt&t == 0 {
- continue
- }
- ff = append(ff, &memFilePtr{ms: ms, num: num, t: mt})
- }
+ ms.meta = fd
ms.mu.Unlock()
- return ff, nil
+ return nil
}
-func (ms *memStorage) GetManifest() (File, error) {
+func (ms *memStorage) GetMeta() (FileDesc, error) {
ms.mu.Lock()
defer ms.mu.Unlock()
- if ms.manifest == nil {
- return nil, os.ErrNotExist
+ if ms.meta.Nil() {
+ return FileDesc{}, os.ErrNotExist
}
- return ms.manifest, nil
+ return ms.meta, nil
}
-func (ms *memStorage) SetManifest(f File) error {
- fm, ok := f.(*memFilePtr)
- if !ok || fm.t != TypeManifest {
- return ErrInvalidFile
- }
+func (ms *memStorage) List(ft FileType) ([]FileDesc, error) {
ms.mu.Lock()
- ms.manifest = fm
+ var fds []FileDesc
+ for x, _ := range ms.files {
+ fd := unpackFile(x)
+ if fd.Type&ft != 0 {
+ fds = append(fds, fd)
+ }
+ }
ms.mu.Unlock()
- return nil
+ return fds, nil
}
-func (*memStorage) Close() error { return nil }
-
-type memReader struct {
- *bytes.Reader
- m *memFile
-}
-
-func (mr *memReader) Close() error {
- return mr.m.Close()
-}
-
-type memFile struct {
- bytes.Buffer
- ms *memStorage
- open bool
-}
-
-func (*memFile) Sync() error { return nil }
-func (m *memFile) Close() error {
- m.ms.mu.Lock()
- m.open = false
- m.ms.mu.Unlock()
- return nil
-}
-
-type memFilePtr struct {
- ms *memStorage
- num uint64
- t FileType
-}
-
-func (p *memFilePtr) x() uint64 {
- return p.Num()<<typeShift | uint64(p.Type())
-}
+func (ms *memStorage) Open(fd FileDesc) (Reader, error) {
+ if !FileDescOk(fd) {
+ return nil, ErrInvalidFile
+ }
-func (p *memFilePtr) Open() (Reader, error) {
- ms := p.ms
ms.mu.Lock()
defer ms.mu.Unlock()
- if m, exist := ms.files[p.x()]; exist {
+ if m, exist := ms.files[packFile(fd)]; exist {
if m.open {
return nil, errFileOpen
}
m.open = true
- return &memReader{Reader: bytes.NewReader(m.Bytes()), m: m}, nil
+ return &memReader{Reader: bytes.NewReader(m.Bytes()), ms: ms, m: m}, nil
}
return nil, os.ErrNotExist
}
-func (p *memFilePtr) Create() (Writer, error) {
- ms := p.ms
+func (ms *memStorage) Create(fd FileDesc) (Writer, error) {
+ if !FileDescOk(fd) {
+ return nil, ErrInvalidFile
+ }
+
+ x := packFile(fd)
ms.mu.Lock()
defer ms.mu.Unlock()
- m, exist := ms.files[p.x()]
+ m, exist := ms.files[x]
if exist {
if m.open {
return nil, errFileOpen
}
m.Reset()
} else {
- m = &memFile{ms: ms}
- ms.files[p.x()] = m
+ m = &memFile{}
+ ms.files[x] = m
}
m.open = true
- return m, nil
+ return &memWriter{memFile: m, ms: ms}, nil
}
-func (p *memFilePtr) Replace(newfile File) error {
- p1, ok := newfile.(*memFilePtr)
- if !ok {
+func (ms *memStorage) Remove(fd FileDesc) error {
+ if !FileDescOk(fd) {
return ErrInvalidFile
}
- ms := p.ms
+
+ x := packFile(fd)
ms.mu.Lock()
defer ms.mu.Unlock()
- m1, exist := ms.files[p1.x()]
+ if _, exist := ms.files[x]; exist {
+ delete(ms.files, x)
+ return nil
+ }
+ return os.ErrNotExist
+}
+
+func (ms *memStorage) Rename(oldfd, newfd FileDesc) error {
+ if FileDescOk(oldfd) || FileDescOk(newfd) {
+ return ErrInvalidFile
+ }
+ if oldfd == newfd {
+ return nil
+ }
+
+ oldx := packFile(oldfd)
+ newx := packFile(newfd)
+ ms.mu.Lock()
+ defer ms.mu.Unlock()
+ oldm, exist := ms.files[oldx]
if !exist {
return os.ErrNotExist
}
- m0, exist := ms.files[p.x()]
- if (exist && m0.open) || m1.open {
+ newm, exist := ms.files[newx]
+ if (exist && newm.open) || oldm.open {
return errFileOpen
}
- delete(ms.files, p1.x())
- ms.files[p.x()] = m1
+ delete(ms.files, oldx)
+ ms.files[newx] = oldm
return nil
}
-func (p *memFilePtr) Type() FileType {
- return p.t
+func (*memStorage) Close() error { return nil }
+
+type memFile struct {
+ bytes.Buffer
+ open bool
}
-func (p *memFilePtr) Num() uint64 {
- return p.num
+type memReader struct {
+ *bytes.Reader
+ ms *memStorage
+ m *memFile
+ closed bool
}
-func (p *memFilePtr) Remove() error {
- ms := p.ms
- ms.mu.Lock()
- defer ms.mu.Unlock()
- if _, exist := ms.files[p.x()]; exist {
- delete(ms.files, p.x())
- return nil
+func (mr *memReader) Close() error {
+ mr.ms.mu.Lock()
+ defer mr.ms.mu.Unlock()
+ if mr.closed {
+ return ErrClosed
}
- return os.ErrNotExist
+ mr.m.open = false
+ return nil
+}
+
+type memWriter struct {
+ *memFile
+ ms *memStorage
+ closed bool
+}
+
+func (*memWriter) Sync() error { return nil }
+
+func (mw *memWriter) Close() error {
+ mw.ms.mu.Lock()
+ defer mw.ms.mu.Unlock()
+ if mw.closed {
+ return ErrClosed
+ }
+ mw.memFile.open = false
+ return nil
+}
+
+func packFile(fd FileDesc) uint64 {
+ return uint64(fd.Num)<<typeShift | uint64(fd.Type)
+}
+
+func unpackFile(x uint64) FileDesc {
+ return FileDesc{FileType(x) & TypeAll, int64(x >> typeShift)}
}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/mem_storage_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/mem_storage_test.go
deleted file mode 100644
index 23bb074b4..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/mem_storage_test.go
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com>
-// All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package storage
-
-import (
- "bytes"
- "testing"
-)
-
-func TestMemStorage(t *testing.T) {
- m := NewMemStorage()
-
- l, err := m.Lock()
- if err != nil {
- t.Fatal("storage lock failed(1): ", err)
- }
- _, err = m.Lock()
- if err == nil {
- t.Fatal("expect error for second storage lock attempt")
- } else {
- t.Logf("storage lock got error: %s (expected)", err)
- }
- l.Release()
- _, err = m.Lock()
- if err != nil {
- t.Fatal("storage lock failed(2): ", err)
- }
-
- f := m.GetFile(1, TypeTable)
- if f.Num() != 1 && f.Type() != TypeTable {
- t.Fatal("invalid file number and type")
- }
- w, _ := f.Create()
- w.Write([]byte("abc"))
- w.Close()
- if ff, _ := m.GetFiles(TypeAll); len(ff) != 1 {
- t.Fatal("invalid GetFiles len")
- }
- buf := new(bytes.Buffer)
- r, err := f.Open()
- if err != nil {
- t.Fatal("Open: got error: ", err)
- }
- buf.ReadFrom(r)
- r.Close()
- if got := buf.String(); got != "abc" {
- t.Fatalf("Read: invalid value, want=abc got=%s", got)
- }
- if _, err := f.Open(); err != nil {
- t.Fatal("Open: got error: ", err)
- }
- if _, err := m.GetFile(1, TypeTable).Open(); err == nil {
- t.Fatal("expecting error")
- }
- f.Remove()
- if ff, _ := m.GetFiles(TypeAll); len(ff) != 0 {
- t.Fatal("invalid GetFiles len", len(ff))
- }
- if _, err := f.Open(); err == nil {
- t.Fatal("expecting error")
- }
-}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/storage.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/storage.go
index 85dd70b06..9b30b6727 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/storage.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage/storage.go
@@ -15,7 +15,7 @@ import (
"github.com/syndtr/goleveldb/leveldb/util"
)
-type FileType uint32
+type FileType int
const (
TypeManifest FileType = 1 << iota
@@ -46,6 +46,22 @@ var (
ErrClosed = errors.New("leveldb/storage: closed")
)
+// ErrCorrupted is the type that wraps errors that indicate corruption of
+// a file. Package storage has its own type instead of using
+// errors.ErrCorrupted to prevent circular import.
+type ErrCorrupted struct {
+ Fd FileDesc
+ Err error
+}
+
+func (e *ErrCorrupted) Error() string {
+ if !e.Fd.Nil() {
+ return fmt.Sprintf("%v [file=%v]", e.Err, e.Fd)
+ } else {
+ return e.Err.Error()
+ }
+}
+
// Syncer is the interface that wraps basic Sync method.
type Syncer interface {
// Sync commits the current contents of the file to stable storage.
@@ -67,31 +83,47 @@ type Writer interface {
Syncer
}
-// File is the file. A file instance must be goroutine-safe.
-type File interface {
- // Open opens the file for read. Returns os.ErrNotExist error
- // if the file does not exist.
- // Returns ErrClosed if the underlying storage is closed.
- Open() (r Reader, err error)
-
- // Create creates the file for writting. Truncate the file if
- // already exist.
- // Returns ErrClosed if the underlying storage is closed.
- Create() (w Writer, err error)
+type Lock interface {
+ util.Releaser
+}
- // Replace replaces file with newfile.
- // Returns ErrClosed if the underlying storage is closed.
- Replace(newfile File) error
+// FileDesc is a file descriptor.
+type FileDesc struct {
+ Type FileType
+ Num int64
+}
- // Type returns the file type
- Type() FileType
+func (fd FileDesc) String() string {
+ switch fd.Type {
+ case TypeManifest:
+ return fmt.Sprintf("MANIFEST-%06d", fd.Num)
+ case TypeJournal:
+ return fmt.Sprintf("%06d.log", fd.Num)
+ case TypeTable:
+ return fmt.Sprintf("%06d.ldb", fd.Num)
+ case TypeTemp:
+ return fmt.Sprintf("%06d.tmp", fd.Num)
+ default:
+ return fmt.Sprintf("%#x-%d", fd.Type, fd.Num)
+ }
+}
- // Num returns the file number.
- Num() uint64
+// Nil returns true if fd == (FileDesc{}).
+func (fd FileDesc) Nil() bool {
+ return fd == (FileDesc{})
+}
- // Remove removes the file.
- // Returns ErrClosed if the underlying storage is closed.
- Remove() error
+// FileDescOk returns true if fd is a valid file descriptor.
+func FileDescOk(fd FileDesc) bool {
+ switch fd.Type {
+ case TypeManifest:
+ case TypeJournal:
+ case TypeTable:
+ case TypeTemp:
+ default:
+ return false
+ }
+ return fd.Num >= 0
}
// Storage is the storage. A storage instance must be goroutine-safe.
@@ -99,59 +131,47 @@ type Storage interface {
// Lock locks the storage. Any subsequent attempt to call Lock will fail
// until the last lock released.
// After use the caller should call the Release method.
- Lock() (l util.Releaser, err error)
+ Lock() (Lock, error)
- // Log logs a string. This is used for logging. An implementation
- // may write to a file, stdout or simply do nothing.
+ // Log logs a string. This is used for logging.
+ // An implementation may write to a file, stdout or simply do nothing.
Log(str string)
- // GetFile returns a file for the given number and type. GetFile will never
- // returns nil, even if the underlying storage is closed.
- GetFile(num uint64, t FileType) File
+ // SetMeta sets to point to the given fd, which then can be acquired using
+ // GetMeta method.
+ // SetMeta should be implemented in such way that changes should happened
+ // atomically.
+ SetMeta(fd FileDesc) error
- // GetFiles returns a slice of files that match the given file types.
- // The file types may be OR'ed together.
- GetFiles(t FileType) ([]File, error)
+ // GetManifest returns a manifest file.
+ // Returns os.ErrNotExist if meta doesn't point to any fd, or point to fd
+ // that doesn't exist.
+ GetMeta() (FileDesc, error)
- // GetManifest returns a manifest file. Returns os.ErrNotExist if manifest
- // file does not exist.
- GetManifest() (File, error)
+ // List returns fds that match the given file types.
+ // The file types may be OR'ed together.
+ List(ft FileType) ([]FileDesc, error)
- // SetManifest sets the given file as manifest file. The given file should
- // be a manifest file type or error will be returned.
- SetManifest(f File) error
+ // Open opens file with the given fd read-only.
+ // Returns os.ErrNotExist error if the file does not exist.
+ // Returns ErrClosed if the underlying storage is closed.
+ Open(fd FileDesc) (Reader, error)
- // Close closes the storage. It is valid to call Close multiple times.
- // Other methods should not be called after the storage has been closed.
- Close() error
-}
+ // Create creates file with the given fd, truncate if already exist and
+ // opens write-only.
+ // Returns ErrClosed if the underlying storage is closed.
+ Create(fd FileDesc) (Writer, error)
-// FileInfo wraps basic file info.
-type FileInfo struct {
- Type FileType
- Num uint64
-}
+ // Remove removes file with the given fd.
+ // Returns ErrClosed if the underlying storage is closed.
+ Remove(fd FileDesc) error
-func (fi FileInfo) String() string {
- switch fi.Type {
- case TypeManifest:
- return fmt.Sprintf("MANIFEST-%06d", fi.Num)
- case TypeJournal:
- return fmt.Sprintf("%06d.log", fi.Num)
- case TypeTable:
- return fmt.Sprintf("%06d.ldb", fi.Num)
- case TypeTemp:
- return fmt.Sprintf("%06d.tmp", fi.Num)
- default:
- return fmt.Sprintf("%#x-%d", fi.Type, fi.Num)
- }
-}
+ // Rename renames file from oldfd to newfd.
+ // Returns ErrClosed if the underlying storage is closed.
+ Rename(oldfd, newfd FileDesc) error
-// NewFileInfo creates new FileInfo from the given File. It will returns nil
-// if File is nil.
-func NewFileInfo(f File) *FileInfo {
- if f == nil {
- return nil
- }
- return &FileInfo{f.Type(), f.Num()}
+ // Close closes the storage.
+ // It is valid to call Close multiple times. Other methods should not be
+ // called after the storage has been closed.
+ Close() error
}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage_test.go
deleted file mode 100644
index dc1f1fb54..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/storage_test.go
+++ /dev/null
@@ -1,539 +0,0 @@
-// Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
-// All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENE file.
-
-package leveldb
-
-import (
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- "math/rand"
- "os"
- "path/filepath"
- "sync"
- "testing"
-
- "github.com/syndtr/goleveldb/leveldb/storage"
- "github.com/syndtr/goleveldb/leveldb/util"
-)
-
-const typeShift = 4
-
-var (
- tsErrInvalidFile = errors.New("leveldb.testStorage: invalid file for argument")
- tsErrFileOpen = errors.New("leveldb.testStorage: file still open")
-)
-
-var (
- tsFSEnv = os.Getenv("GOLEVELDB_USEFS")
- tsTempdir = os.Getenv("GOLEVELDB_TEMPDIR")
- tsKeepFS = tsFSEnv == "2"
- tsFS = tsKeepFS || tsFSEnv == "" || tsFSEnv == "1"
- tsMU = &sync.Mutex{}
- tsNum = 0
-)
-
-type tsOp uint
-
-const (
- tsOpOpen tsOp = iota
- tsOpCreate
- tsOpRead
- tsOpReadAt
- tsOpWrite
- tsOpSync
-
- tsOpNum
-)
-
-type tsLock struct {
- ts *testStorage
- r util.Releaser
-}
-
-func (l tsLock) Release() {
- l.r.Release()
- l.ts.t.Log("I: storage lock released")
-}
-
-type tsReader struct {
- tf tsFile
- storage.Reader
-}
-
-func (tr tsReader) Read(b []byte) (n int, err error) {
- ts := tr.tf.ts
- ts.countRead(tr.tf.Type())
- if tr.tf.shouldErrLocked(tsOpRead) {
- return 0, errors.New("leveldb.testStorage: emulated read error")
- }
- n, err = tr.Reader.Read(b)
- if err != nil && err != io.EOF {
- ts.t.Errorf("E: read error, num=%d type=%v n=%d: %v", tr.tf.Num(), tr.tf.Type(), n, err)
- }
- return
-}
-
-func (tr tsReader) ReadAt(b []byte, off int64) (n int, err error) {
- ts := tr.tf.ts
- ts.countRead(tr.tf.Type())
- if tr.tf.shouldErrLocked(tsOpReadAt) {
- return 0, errors.New("leveldb.testStorage: emulated readAt error")
- }
- n, err = tr.Reader.ReadAt(b, off)
- if err != nil && err != io.EOF {
- ts.t.Errorf("E: readAt error, num=%d type=%v off=%d n=%d: %v", tr.tf.Num(), tr.tf.Type(), off, n, err)
- }
- return
-}
-
-func (tr tsReader) Close() (err error) {
- err = tr.Reader.Close()
- tr.tf.close("reader", err)
- return
-}
-
-type tsWriter struct {
- tf tsFile
- storage.Writer
-}
-
-func (tw tsWriter) Write(b []byte) (n int, err error) {
- if tw.tf.shouldErrLocked(tsOpWrite) {
- return 0, errors.New("leveldb.testStorage: emulated write error")
- }
- n, err = tw.Writer.Write(b)
- if err != nil {
- tw.tf.ts.t.Errorf("E: write error, num=%d type=%v n=%d: %v", tw.tf.Num(), tw.tf.Type(), n, err)
- }
- return
-}
-
-func (tw tsWriter) Sync() (err error) {
- ts := tw.tf.ts
- ts.mu.Lock()
- for ts.emuDelaySync&tw.tf.Type() != 0 {
- ts.cond.Wait()
- }
- ts.mu.Unlock()
- if tw.tf.shouldErrLocked(tsOpSync) {
- return errors.New("leveldb.testStorage: emulated sync error")
- }
- err = tw.Writer.Sync()
- if err != nil {
- tw.tf.ts.t.Errorf("E: sync error, num=%d type=%v: %v", tw.tf.Num(), tw.tf.Type(), err)
- }
- return
-}
-
-func (tw tsWriter) Close() (err error) {
- err = tw.Writer.Close()
- tw.tf.close("writer", err)
- return
-}
-
-type tsFile struct {
- ts *testStorage
- storage.File
-}
-
-func (tf tsFile) x() uint64 {
- return tf.Num()<<typeShift | uint64(tf.Type())
-}
-
-func (tf tsFile) shouldErr(op tsOp) bool {
- return tf.ts.shouldErr(tf, op)
-}
-
-func (tf tsFile) shouldErrLocked(op tsOp) bool {
- tf.ts.mu.Lock()
- defer tf.ts.mu.Unlock()
- return tf.shouldErr(op)
-}
-
-func (tf tsFile) checkOpen(m string) error {
- ts := tf.ts
- if writer, ok := ts.opens[tf.x()]; ok {
- if writer {
- ts.t.Errorf("E: cannot %s file, num=%d type=%v: a writer still open", m, tf.Num(), tf.Type())
- } else {
- ts.t.Errorf("E: cannot %s file, num=%d type=%v: a reader still open", m, tf.Num(), tf.Type())
- }
- return tsErrFileOpen
- }
- return nil
-}
-
-func (tf tsFile) close(m string, err error) {
- ts := tf.ts
- ts.mu.Lock()
- defer ts.mu.Unlock()
- if _, ok := ts.opens[tf.x()]; !ok {
- ts.t.Errorf("E: %s: redudant file closing, num=%d type=%v", m, tf.Num(), tf.Type())
- } else if err == nil {
- ts.t.Logf("I: %s: file closed, num=%d type=%v", m, tf.Num(), tf.Type())
- }
- delete(ts.opens, tf.x())
- if err != nil {
- ts.t.Errorf("E: %s: cannot close file, num=%d type=%v: %v", m, tf.Num(), tf.Type(), err)
- }
-}
-
-func (tf tsFile) Open() (r storage.Reader, err error) {
- ts := tf.ts
- ts.mu.Lock()
- defer ts.mu.Unlock()
- err = tf.checkOpen("open")
- if err != nil {
- return
- }
- if tf.shouldErr(tsOpOpen) {
- err = errors.New("leveldb.testStorage: emulated open error")
- return
- }
- r, err = tf.File.Open()
- if err != nil {
- if ts.ignoreOpenErr&tf.Type() != 0 {
- ts.t.Logf("I: cannot open file, num=%d type=%v: %v (ignored)", tf.Num(), tf.Type(), err)
- } else {
- ts.t.Errorf("E: cannot open file, num=%d type=%v: %v", tf.Num(), tf.Type(), err)
- }
- } else {
- ts.t.Logf("I: file opened, num=%d type=%v", tf.Num(), tf.Type())
- ts.opens[tf.x()] = false
- r = tsReader{tf, r}
- }
- return
-}
-
-func (tf tsFile) Create() (w storage.Writer, err error) {
- ts := tf.ts
- ts.mu.Lock()
- defer ts.mu.Unlock()
- err = tf.checkOpen("create")
- if err != nil {
- return
- }
- if tf.shouldErr(tsOpCreate) {
- err = errors.New("leveldb.testStorage: emulated create error")
- return
- }
- w, err = tf.File.Create()
- if err != nil {
- ts.t.Errorf("E: cannot create file, num=%d type=%v: %v", tf.Num(), tf.Type(), err)
- } else {
- ts.t.Logf("I: file created, num=%d type=%v", tf.Num(), tf.Type())
- ts.opens[tf.x()] = true
- w = tsWriter{tf, w}
- }
- return
-}
-
-func (tf tsFile) Replace(newfile storage.File) (err error) {
- ts := tf.ts
- ts.mu.Lock()
- defer ts.mu.Unlock()
- err = tf.checkOpen("replace")
- if err != nil {
- return
- }
- err = tf.File.Replace(newfile.(tsFile).File)
- if err != nil {
- ts.t.Errorf("E: cannot replace file, num=%d type=%v: %v", tf.Num(), tf.Type(), err)
- } else {
- ts.t.Logf("I: file replace, num=%d type=%v", tf.Num(), tf.Type())
- }
- return
-}
-
-func (tf tsFile) Remove() (err error) {
- ts := tf.ts
- ts.mu.Lock()
- defer ts.mu.Unlock()
- err = tf.checkOpen("remove")
- if err != nil {
- return
- }
- err = tf.File.Remove()
- if err != nil {
- ts.t.Errorf("E: cannot remove file, num=%d type=%v: %v", tf.Num(), tf.Type(), err)
- } else {
- ts.t.Logf("I: file removed, num=%d type=%v", tf.Num(), tf.Type())
- }
- return
-}
-
-type testStorage struct {
- t *testing.T
- storage.Storage
- closeFn func() error
-
- mu sync.Mutex
- cond sync.Cond
- // Open files, true=writer, false=reader
- opens map[uint64]bool
- emuDelaySync storage.FileType
- ignoreOpenErr storage.FileType
- readCnt uint64
- readCntEn storage.FileType
-
- emuErr [tsOpNum]storage.FileType
- emuErrOnce [tsOpNum]storage.FileType
- emuRandErr [tsOpNum]storage.FileType
- emuRandErrProb int
- emuErrOnceMap map[uint64]uint
- emuRandRand *rand.Rand
-}
-
-func (ts *testStorage) shouldErr(tf tsFile, op tsOp) bool {
- if ts.emuErr[op]&tf.Type() != 0 {
- return true
- } else if ts.emuRandErr[op]&tf.Type() != 0 || ts.emuErrOnce[op]&tf.Type() != 0 {
- sop := uint(1) << op
- eop := ts.emuErrOnceMap[tf.x()]
- if eop&sop == 0 && (ts.emuRandRand.Int()%ts.emuRandErrProb == 0 || ts.emuErrOnce[op]&tf.Type() != 0) {
- ts.emuErrOnceMap[tf.x()] = eop | sop
- ts.t.Logf("I: emulated error: file=%d type=%v op=%v", tf.Num(), tf.Type(), op)
- return true
- }
- }
- return false
-}
-
-func (ts *testStorage) SetEmuErr(t storage.FileType, ops ...tsOp) {
- ts.mu.Lock()
- for _, op := range ops {
- ts.emuErr[op] = t
- }
- ts.mu.Unlock()
-}
-
-func (ts *testStorage) SetEmuErrOnce(t storage.FileType, ops ...tsOp) {
- ts.mu.Lock()
- for _, op := range ops {
- ts.emuErrOnce[op] = t
- }
- ts.mu.Unlock()
-}
-
-func (ts *testStorage) SetEmuRandErr(t storage.FileType, ops ...tsOp) {
- ts.mu.Lock()
- for _, op := range ops {
- ts.emuRandErr[op] = t
- }
- ts.mu.Unlock()
-}
-
-func (ts *testStorage) SetEmuRandErrProb(prob int) {
- ts.mu.Lock()
- ts.emuRandErrProb = prob
- ts.mu.Unlock()
-}
-
-func (ts *testStorage) DelaySync(t storage.FileType) {
- ts.mu.Lock()
- ts.emuDelaySync |= t
- ts.cond.Broadcast()
- ts.mu.Unlock()
-}
-
-func (ts *testStorage) ReleaseSync(t storage.FileType) {
- ts.mu.Lock()
- ts.emuDelaySync &= ^t
- ts.cond.Broadcast()
- ts.mu.Unlock()
-}
-
-func (ts *testStorage) ReadCounter() uint64 {
- ts.mu.Lock()
- defer ts.mu.Unlock()
- return ts.readCnt
-}
-
-func (ts *testStorage) ResetReadCounter() {
- ts.mu.Lock()
- ts.readCnt = 0
- ts.mu.Unlock()
-}
-
-func (ts *testStorage) SetReadCounter(t storage.FileType) {
- ts.mu.Lock()
- ts.readCntEn = t
- ts.mu.Unlock()
-}
-
-func (ts *testStorage) countRead(t storage.FileType) {
- ts.mu.Lock()
- if ts.readCntEn&t != 0 {
- ts.readCnt++
- }
- ts.mu.Unlock()
-}
-
-func (ts *testStorage) SetIgnoreOpenErr(t storage.FileType) {
- ts.ignoreOpenErr = t
-}
-
-func (ts *testStorage) Lock() (r util.Releaser, err error) {
- r, err = ts.Storage.Lock()
- if err != nil {
- ts.t.Logf("W: storage locking failed: %v", err)
- } else {
- ts.t.Log("I: storage locked")
- r = tsLock{ts, r}
- }
- return
-}
-
-func (ts *testStorage) Log(str string) {
- ts.t.Log("L: " + str)
- ts.Storage.Log(str)
-}
-
-func (ts *testStorage) GetFile(num uint64, t storage.FileType) storage.File {
- return tsFile{ts, ts.Storage.GetFile(num, t)}
-}
-
-func (ts *testStorage) GetFiles(t storage.FileType) (ff []storage.File, err error) {
- ff0, err := ts.Storage.GetFiles(t)
- if err != nil {
- ts.t.Errorf("E: get files failed: %v", err)
- return
- }
- ff = make([]storage.File, len(ff0))
- for i, f := range ff0 {
- ff[i] = tsFile{ts, f}
- }
- ts.t.Logf("I: get files, type=0x%x count=%d", int(t), len(ff))
- return
-}
-
-func (ts *testStorage) GetManifest() (f storage.File, err error) {
- f0, err := ts.Storage.GetManifest()
- if err != nil {
- if !os.IsNotExist(err) {
- ts.t.Errorf("E: get manifest failed: %v", err)
- }
- return
- }
- f = tsFile{ts, f0}
- ts.t.Logf("I: get manifest, num=%d", f.Num())
- return
-}
-
-func (ts *testStorage) SetManifest(f storage.File) error {
- tf, ok := f.(tsFile)
- if !ok {
- ts.t.Error("E: set manifest failed: type assertion failed")
- return tsErrInvalidFile
- } else if tf.Type() != storage.TypeManifest {
- ts.t.Errorf("E: set manifest failed: invalid file type: %s", tf.Type())
- return tsErrInvalidFile
- }
- err := ts.Storage.SetManifest(tf.File)
- if err != nil {
- ts.t.Errorf("E: set manifest failed: %v", err)
- } else {
- ts.t.Logf("I: set manifest, num=%d", tf.Num())
- }
- return err
-}
-
-func (ts *testStorage) Close() error {
- ts.CloseCheck()
- err := ts.Storage.Close()
- if err != nil {
- ts.t.Errorf("E: closing storage failed: %v", err)
- } else {
- ts.t.Log("I: storage closed")
- }
- if ts.closeFn != nil {
- if err := ts.closeFn(); err != nil {
- ts.t.Errorf("E: close function: %v", err)
- }
- }
- return err
-}
-
-func (ts *testStorage) CloseCheck() {
- ts.mu.Lock()
- if len(ts.opens) == 0 {
- ts.t.Log("I: all files are closed")
- } else {
- ts.t.Errorf("E: %d files still open", len(ts.opens))
- for x, writer := range ts.opens {
- num, tt := x>>typeShift, storage.FileType(x)&storage.TypeAll
- ts.t.Errorf("E: * num=%d type=%v writer=%v", num, tt, writer)
- }
- }
- ts.mu.Unlock()
-}
-
-func newTestStorage(t *testing.T) *testStorage {
- var stor storage.Storage
- var closeFn func() error
- if tsFS {
- for {
- tsMU.Lock()
- num := tsNum
- tsNum++
- tsMU.Unlock()
- tempdir := tsTempdir
- if tempdir == "" {
- tempdir = os.TempDir()
- }
- path := filepath.Join(tempdir, fmt.Sprintf("goleveldb-test%d0%d0%d", os.Getuid(), os.Getpid(), num))
- if _, err := os.Stat(path); err != nil {
- stor, err = storage.OpenFile(path)
- if err != nil {
- t.Fatalf("F: cannot create storage: %v", err)
- }
- t.Logf("I: storage created: %s", path)
- closeFn = func() error {
- for _, name := range []string{"LOG.old", "LOG"} {
- f, err := os.Open(filepath.Join(path, name))
- if err != nil {
- continue
- }
- if log, err := ioutil.ReadAll(f); err != nil {
- t.Logf("---------------------- %s ----------------------", name)
- t.Logf("cannot read log: %v", err)
- t.Logf("---------------------- %s ----------------------", name)
- } else if len(log) > 0 {
- t.Logf("---------------------- %s ----------------------\n%s", name, string(log))
- t.Logf("---------------------- %s ----------------------", name)
- }
- f.Close()
- }
- if t.Failed() {
- t.Logf("testing failed, test DB preserved at %s", path)
- return nil
- }
- if tsKeepFS {
- return nil
- }
- return os.RemoveAll(path)
- }
-
- break
- }
- }
- } else {
- stor = storage.NewMemStorage()
- }
- ts := &testStorage{
- t: t,
- Storage: stor,
- closeFn: closeFn,
- opens: make(map[uint64]bool),
- emuErrOnceMap: make(map[uint64]uint),
- emuRandErrProb: 0x999,
- emuRandRand: rand.New(rand.NewSource(0xfacedead)),
- }
- ts.cond.L = &ts.mu
- return ts
-}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table.go
index 3e8df6af5..7030b22ef 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table.go
@@ -21,9 +21,9 @@ import (
// tFile holds basic information about a table.
type tFile struct {
- file storage.File
+ fd storage.FileDesc
seekLeft int32
- size uint64
+ size int64
imin, imax iKey
}
@@ -48,9 +48,9 @@ func (t *tFile) consumeSeek() int32 {
}
// Creates new tFile.
-func newTableFile(file storage.File, size uint64, imin, imax iKey) *tFile {
+func newTableFile(fd storage.FileDesc, size int64, imin, imax iKey) *tFile {
f := &tFile{
- file: file,
+ fd: fd,
size: size,
imin: imin,
imax: imax,
@@ -77,6 +77,10 @@ func newTableFile(file storage.File, size uint64, imin, imax iKey) *tFile {
return f
}
+func tableFileFromRecord(r atRecord) *tFile {
+ return newTableFile(storage.FileDesc{storage.TypeTable, r.num}, r.size, r.imin, r.imax)
+}
+
// tFiles hold multiple tFile.
type tFiles []*tFile
@@ -89,7 +93,7 @@ func (tf tFiles) nums() string {
if i != 0 {
x += ", "
}
- x += fmt.Sprint(f.file.Num())
+ x += fmt.Sprint(f.fd.Num)
}
x += " ]"
return x
@@ -101,7 +105,7 @@ func (tf tFiles) lessByKey(icmp *iComparer, i, j int) bool {
a, b := tf[i], tf[j]
n := icmp.Compare(a.imin, b.imin)
if n == 0 {
- return a.file.Num() < b.file.Num()
+ return a.fd.Num < b.fd.Num
}
return n < 0
}
@@ -109,7 +113,7 @@ func (tf tFiles) lessByKey(icmp *iComparer, i, j int) bool {
// Returns true if i file number is greater than j.
// This used for sort by file number in descending order.
func (tf tFiles) lessByNum(i, j int) bool {
- return tf[i].file.Num() > tf[j].file.Num()
+ return tf[i].fd.Num > tf[j].fd.Num
}
// Sorts tables by key in ascending order.
@@ -123,7 +127,7 @@ func (tf tFiles) sortByNum() {
}
// Returns sum of all tables size.
-func (tf tFiles) size() (sum uint64) {
+func (tf tFiles) size() (sum int64) {
for _, t := range tf {
sum += t.size
}
@@ -162,7 +166,7 @@ func (tf tFiles) overlaps(icmp *iComparer, umin, umax []byte, unsorted bool) boo
i := 0
if len(umin) > 0 {
// Find the earliest possible internal key for min.
- i = tf.searchMax(icmp, newIkey(umin, kMaxSeq, ktSeek))
+ i = tf.searchMax(icmp, makeIkey(nil, umin, kMaxSeq, ktSeek))
}
if i >= len(tf) {
// Beginning of range is after all files, so no overlap.
@@ -287,6 +291,7 @@ func (x *tFilesSortByNum) Less(i, j int) bool {
// Table operations.
type tOps struct {
s *session
+ noSync bool
cache *cache.Cache
bcache *cache.Cache
bpool *util.BufferPool
@@ -294,16 +299,16 @@ type tOps struct {
// Creates an empty table and returns table writer.
func (t *tOps) create() (*tWriter, error) {
- file := t.s.getTableFile(t.s.allocFileNum())
- fw, err := file.Create()
+ fd := storage.FileDesc{storage.TypeTable, t.s.allocFileNum()}
+ fw, err := t.s.stor.Create(fd)
if err != nil {
return nil, err
}
return &tWriter{
- t: t,
- file: file,
- w: fw,
- tw: table.NewWriter(fw, t.s.o.Options),
+ t: t,
+ fd: fd,
+ w: fw,
+ tw: table.NewWriter(fw, t.s.o.Options),
}, nil
}
@@ -339,21 +344,20 @@ func (t *tOps) createFrom(src iterator.Iterator) (f *tFile, n int, err error) {
// Opens table. It returns a cache handle, which should
// be released after use.
func (t *tOps) open(f *tFile) (ch *cache.Handle, err error) {
- num := f.file.Num()
- ch = t.cache.Get(0, num, func() (size int, value cache.Value) {
+ ch = t.cache.Get(0, uint64(f.fd.Num), func() (size int, value cache.Value) {
var r storage.Reader
- r, err = f.file.Open()
+ r, err = t.s.stor.Open(f.fd)
if err != nil {
return 0, nil
}
var bcache *cache.CacheGetter
if t.bcache != nil {
- bcache = &cache.CacheGetter{Cache: t.bcache, NS: num}
+ bcache = &cache.CacheGetter{Cache: t.bcache, NS: uint64(f.fd.Num)}
}
var tr *table.Reader
- tr, err = table.NewReader(r, int64(f.size), storage.NewFileInfo(f.file), bcache, t.bpool, t.s.o.Options)
+ tr, err = table.NewReader(r, f.size, f.fd, bcache, t.bpool, t.s.o.Options)
if err != nil {
r.Close()
return 0, nil
@@ -413,15 +417,14 @@ func (t *tOps) newIterator(f *tFile, slice *util.Range, ro *opt.ReadOptions) ite
// Removes table from persistent storage. It waits until
// no one use the the table.
func (t *tOps) remove(f *tFile) {
- num := f.file.Num()
- t.cache.Delete(0, num, func() {
- if err := f.file.Remove(); err != nil {
- t.s.logf("table@remove removing @%d %q", num, err)
+ t.cache.Delete(0, uint64(f.fd.Num), func() {
+ if err := t.s.stor.Remove(f.fd); err != nil {
+ t.s.logf("table@remove removing @%d %q", f.fd.Num, err)
} else {
- t.s.logf("table@remove removed @%d", num)
+ t.s.logf("table@remove removed @%d", f.fd.Num)
}
if t.bcache != nil {
- t.bcache.EvictNS(num)
+ t.bcache.EvictNS(uint64(f.fd.Num))
}
})
}
@@ -441,22 +444,27 @@ func newTableOps(s *session) *tOps {
var (
cacher cache.Cacher
bcache *cache.Cache
+ bpool *util.BufferPool
)
if s.o.GetOpenFilesCacheCapacity() > 0 {
cacher = cache.NewLRU(s.o.GetOpenFilesCacheCapacity())
}
- if !s.o.DisableBlockCache {
+ if !s.o.GetDisableBlockCache() {
var bcacher cache.Cacher
if s.o.GetBlockCacheCapacity() > 0 {
bcacher = cache.NewLRU(s.o.GetBlockCacheCapacity())
}
bcache = cache.NewCache(bcacher)
}
+ if !s.o.GetDisableBufferPool() {
+ bpool = util.NewBufferPool(s.o.GetBlockSize() + 5)
+ }
return &tOps{
s: s,
+ noSync: s.o.GetNoSync(),
cache: cache.NewCache(cacher),
bcache: bcache,
- bpool: util.NewBufferPool(s.o.GetBlockSize() + 5),
+ bpool: bpool,
}
}
@@ -465,9 +473,9 @@ func newTableOps(s *session) *tOps {
type tWriter struct {
t *tOps
- file storage.File
- w storage.Writer
- tw *table.Writer
+ fd storage.FileDesc
+ w storage.Writer
+ tw *table.Writer
first, last []byte
}
@@ -501,20 +509,21 @@ func (w *tWriter) finish() (f *tFile, err error) {
if err != nil {
return
}
- err = w.w.Sync()
- if err != nil {
- return
+ if !w.t.noSync {
+ err = w.w.Sync()
+ if err != nil {
+ return
+ }
}
- f = newTableFile(w.file, uint64(w.tw.BytesLen()), iKey(w.first), iKey(w.last))
+ f = newTableFile(w.fd, int64(w.tw.BytesLen()), iKey(w.first), iKey(w.last))
return
}
// Drops the table.
func (w *tWriter) drop() {
w.close()
- w.file.Remove()
- w.t.s.reuseFileNum(w.file.Num())
- w.file = nil
+ w.t.s.stor.Remove(w.fd)
+ w.t.s.reuseFileNum(w.fd.Num)
w.tw = nil
w.first = nil
w.last = nil
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/block_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/block_test.go
deleted file mode 100644
index 00e6f9eea..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/block_test.go
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright (c) 2014, Suryandaru Triandana <syndtr@gmail.com>
-// All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package table
-
-import (
- "encoding/binary"
- "fmt"
-
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-
- "github.com/syndtr/goleveldb/leveldb/comparer"
- "github.com/syndtr/goleveldb/leveldb/iterator"
- "github.com/syndtr/goleveldb/leveldb/testutil"
- "github.com/syndtr/goleveldb/leveldb/util"
-)
-
-type blockTesting struct {
- tr *Reader
- b *block
-}
-
-func (t *blockTesting) TestNewIterator(slice *util.Range) iterator.Iterator {
- return t.tr.newBlockIter(t.b, nil, slice, false)
-}
-
-var _ = testutil.Defer(func() {
- Describe("Block", func() {
- Build := func(kv *testutil.KeyValue, restartInterval int) *blockTesting {
- // Building the block.
- bw := &blockWriter{
- restartInterval: restartInterval,
- scratch: make([]byte, 30),
- }
- kv.Iterate(func(i int, key, value []byte) {
- bw.append(key, value)
- })
- bw.finish()
-
- // Opening the block.
- data := bw.buf.Bytes()
- restartsLen := int(binary.LittleEndian.Uint32(data[len(data)-4:]))
- return &blockTesting{
- tr: &Reader{cmp: comparer.DefaultComparer},
- b: &block{
- data: data,
- restartsLen: restartsLen,
- restartsOffset: len(data) - (restartsLen+1)*4,
- },
- }
- }
-
- Describe("read test", func() {
- for restartInterval := 1; restartInterval <= 5; restartInterval++ {
- Describe(fmt.Sprintf("with restart interval of %d", restartInterval), func() {
- kv := &testutil.KeyValue{}
- Text := func() string {
- return fmt.Sprintf("and %d keys", kv.Len())
- }
-
- Test := func() {
- // Make block.
- br := Build(kv, restartInterval)
- // Do testing.
- testutil.KeyValueTesting(nil, kv.Clone(), br, nil, nil)
- }
-
- Describe(Text(), Test)
-
- kv.PutString("", "empty")
- Describe(Text(), Test)
-
- kv.PutString("a1", "foo")
- Describe(Text(), Test)
-
- kv.PutString("a2", "v")
- Describe(Text(), Test)
-
- kv.PutString("a3qqwrkks", "hello")
- Describe(Text(), Test)
-
- kv.PutString("a4", "bar")
- Describe(Text(), Test)
-
- kv.PutString("a5111111", "v5")
- kv.PutString("a6", "")
- kv.PutString("a7", "v7")
- kv.PutString("a8", "vvvvvvvvvvvvvvvvvvvvvv8")
- kv.PutString("b", "v9")
- kv.PutString("c9", "v9")
- kv.PutString("c91", "v9")
- kv.PutString("d0", "v9")
- Describe(Text(), Test)
- })
- }
- })
-
- Describe("out-of-bound slice test", func() {
- kv := &testutil.KeyValue{}
- kv.PutString("k1", "v1")
- kv.PutString("k2", "v2")
- kv.PutString("k3abcdefgg", "v3")
- kv.PutString("k4", "v4")
- kv.PutString("k5", "v5")
- for restartInterval := 1; restartInterval <= 5; restartInterval++ {
- Describe(fmt.Sprintf("with restart interval of %d", restartInterval), func() {
- // Make block.
- bt := Build(kv, restartInterval)
-
- Test := func(r *util.Range) func(done Done) {
- return func(done Done) {
- iter := bt.TestNewIterator(r)
- Expect(iter.Error()).ShouldNot(HaveOccurred())
-
- t := testutil.IteratorTesting{
- KeyValue: kv.Clone(),
- Iter: iter,
- }
-
- testutil.DoIteratorTesting(&t)
- iter.Release()
- done <- true
- }
- }
-
- It("Should do iterations and seeks correctly #0",
- Test(&util.Range{Start: []byte("k0"), Limit: []byte("k6")}), 2.0)
-
- It("Should do iterations and seeks correctly #1",
- Test(&util.Range{Start: []byte(""), Limit: []byte("zzzzzzz")}), 2.0)
- })
- }
- })
- })
-})
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/reader.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/reader.go
index 6f38e84b3..caeac96b5 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/reader.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/reader.go
@@ -14,7 +14,7 @@ import (
"strings"
"sync"
- "github.com/syndtr/gosnappy/snappy"
+ "github.com/golang/snappy"
"github.com/syndtr/goleveldb/leveldb/cache"
"github.com/syndtr/goleveldb/leveldb/comparer"
@@ -507,7 +507,7 @@ func (i *indexIter) Get() iterator.Iterator {
// Reader is a table reader.
type Reader struct {
mu sync.RWMutex
- fi *storage.FileInfo
+ fd storage.FileDesc
reader io.ReaderAt
cache *cache.CacheGetter
err error
@@ -539,7 +539,7 @@ func (r *Reader) blockKind(bh blockHandle) string {
}
func (r *Reader) newErrCorrupted(pos, size int64, kind, reason string) error {
- return &errors.ErrCorrupted{File: r.fi, Err: &ErrCorrupted{Pos: pos, Size: size, Kind: kind, Reason: reason}}
+ return &errors.ErrCorrupted{Fd: r.fd, Err: &ErrCorrupted{Pos: pos, Size: size, Kind: kind, Reason: reason}}
}
func (r *Reader) newErrCorruptedBH(bh blockHandle, reason string) error {
@@ -551,7 +551,7 @@ func (r *Reader) fixErrCorruptedBH(bh blockHandle, err error) error {
cerr.Pos = int64(bh.offset)
cerr.Size = int64(bh.length)
cerr.Kind = r.blockKind(bh)
- return &errors.ErrCorrupted{File: r.fi, Err: cerr}
+ return &errors.ErrCorrupted{Fd: r.fd, Err: cerr}
}
return err
}
@@ -988,13 +988,13 @@ func (r *Reader) Release() {
// The fi, cache and bpool is optional and can be nil.
//
// The returned table reader instance is goroutine-safe.
-func NewReader(f io.ReaderAt, size int64, fi *storage.FileInfo, cache *cache.CacheGetter, bpool *util.BufferPool, o *opt.Options) (*Reader, error) {
+func NewReader(f io.ReaderAt, size int64, fd storage.FileDesc, cache *cache.CacheGetter, bpool *util.BufferPool, o *opt.Options) (*Reader, error) {
if f == nil {
return nil, errors.New("leveldb/table: nil file")
}
r := &Reader{
- fi: fi,
+ fd: fd,
reader: f,
cache: cache,
bpool: bpool,
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/table_suite_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/table_suite_test.go
deleted file mode 100644
index 6465da6e3..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/table_suite_test.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package table
-
-import (
- "testing"
-
- "github.com/syndtr/goleveldb/leveldb/testutil"
-)
-
-func TestTable(t *testing.T) {
- testutil.RunSuite(t, "Table Suite")
-}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/table_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/table_test.go
deleted file mode 100644
index 4b59b31f5..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/table_test.go
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright (c) 2014, Suryandaru Triandana <syndtr@gmail.com>
-// All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package table
-
-import (
- "bytes"
-
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-
- "github.com/syndtr/goleveldb/leveldb/iterator"
- "github.com/syndtr/goleveldb/leveldb/opt"
- "github.com/syndtr/goleveldb/leveldb/testutil"
- "github.com/syndtr/goleveldb/leveldb/util"
-)
-
-type tableWrapper struct {
- *Reader
-}
-
-func (t tableWrapper) TestFind(key []byte) (rkey, rvalue []byte, err error) {
- return t.Reader.Find(key, false, nil)
-}
-
-func (t tableWrapper) TestGet(key []byte) (value []byte, err error) {
- return t.Reader.Get(key, nil)
-}
-
-func (t tableWrapper) TestNewIterator(slice *util.Range) iterator.Iterator {
- return t.Reader.NewIterator(slice, nil)
-}
-
-var _ = testutil.Defer(func() {
- Describe("Table", func() {
- Describe("approximate offset test", func() {
- var (
- buf = &bytes.Buffer{}
- o = &opt.Options{
- BlockSize: 1024,
- Compression: opt.NoCompression,
- }
- )
-
- // Building the table.
- tw := NewWriter(buf, o)
- tw.Append([]byte("k01"), []byte("hello"))
- tw.Append([]byte("k02"), []byte("hello2"))
- tw.Append([]byte("k03"), bytes.Repeat([]byte{'x'}, 10000))
- tw.Append([]byte("k04"), bytes.Repeat([]byte{'x'}, 200000))
- tw.Append([]byte("k05"), bytes.Repeat([]byte{'x'}, 300000))
- tw.Append([]byte("k06"), []byte("hello3"))
- tw.Append([]byte("k07"), bytes.Repeat([]byte{'x'}, 100000))
- err := tw.Close()
-
- It("Should be able to approximate offset of a key correctly", func() {
- Expect(err).ShouldNot(HaveOccurred())
-
- tr, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()), nil, nil, nil, o)
- Expect(err).ShouldNot(HaveOccurred())
- CheckOffset := func(key string, expect, threshold int) {
- offset, err := tr.OffsetOf([]byte(key))
- Expect(err).ShouldNot(HaveOccurred())
- Expect(offset).Should(BeNumerically("~", expect, threshold), "Offset of key %q", key)
- }
-
- CheckOffset("k0", 0, 0)
- CheckOffset("k01a", 0, 0)
- CheckOffset("k02", 0, 0)
- CheckOffset("k03", 0, 0)
- CheckOffset("k04", 10000, 1000)
- CheckOffset("k04a", 210000, 1000)
- CheckOffset("k05", 210000, 1000)
- CheckOffset("k06", 510000, 1000)
- CheckOffset("k07", 510000, 1000)
- CheckOffset("xyz", 610000, 2000)
- })
- })
-
- Describe("read test", func() {
- Build := func(kv testutil.KeyValue) testutil.DB {
- o := &opt.Options{
- BlockSize: 512,
- BlockRestartInterval: 3,
- }
- buf := &bytes.Buffer{}
-
- // Building the table.
- tw := NewWriter(buf, o)
- kv.Iterate(func(i int, key, value []byte) {
- tw.Append(key, value)
- })
- tw.Close()
-
- // Opening the table.
- tr, _ := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()), nil, nil, nil, o)
- return tableWrapper{tr}
- }
- Test := func(kv *testutil.KeyValue, body func(r *Reader)) func() {
- return func() {
- db := Build(*kv)
- if body != nil {
- body(db.(tableWrapper).Reader)
- }
- testutil.KeyValueTesting(nil, *kv, db, nil, nil)
- }
- }
-
- testutil.AllKeyValueTesting(nil, Build, nil, nil)
- Describe("with one key per block", Test(testutil.KeyValue_Generate(nil, 9, 1, 10, 512, 512), func(r *Reader) {
- It("should have correct blocks number", func() {
- indexBlock, err := r.readBlock(r.indexBH, true)
- Expect(err).To(BeNil())
- Expect(indexBlock.restartsLen).Should(Equal(9))
- })
- }))
- })
- })
-})
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/writer.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/writer.go
index 274c95fad..274dee6da 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/writer.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/writer.go
@@ -12,7 +12,7 @@ import (
"fmt"
"io"
- "github.com/syndtr/gosnappy/snappy"
+ "github.com/golang/snappy"
"github.com/syndtr/goleveldb/leveldb/comparer"
"github.com/syndtr/goleveldb/leveldb/filter"
@@ -167,11 +167,7 @@ func (w *Writer) writeBlock(buf *util.Buffer, compression opt.Compression) (bh b
if n := snappy.MaxEncodedLen(buf.Len()) + blockTrailerLen; len(w.compressionScratch) < n {
w.compressionScratch = make([]byte, n)
}
- var compressed []byte
- compressed, err = snappy.Encode(w.compressionScratch, buf.Bytes())
- if err != nil {
- return
- }
+ compressed := snappy.Encode(w.compressionScratch, buf.Bytes())
n := len(compressed)
b = compressed[:n+blockTrailerLen]
b[n] = blockTypeSnappyCompression
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/kvtest.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/kvtest.go
index a0b58f0e7..19d29dfc4 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/kvtest.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/kvtest.go
@@ -17,6 +17,84 @@ import (
"github.com/syndtr/goleveldb/leveldb/util"
)
+func TestFind(db Find, kv KeyValue) {
+ ShuffledIndex(nil, kv.Len(), 1, func(i int) {
+ key_, key, value := kv.IndexInexact(i)
+
+ // Using exact key.
+ rkey, rvalue, err := db.TestFind(key)
+ Expect(err).ShouldNot(HaveOccurred(), "Error for key %q", key)
+ Expect(rkey).Should(Equal(key), "Key")
+ Expect(rvalue).Should(Equal(value), "Value for key %q", key)
+
+ // Using inexact key.
+ rkey, rvalue, err = db.TestFind(key_)
+ Expect(err).ShouldNot(HaveOccurred(), "Error for key %q (%q)", key_, key)
+ Expect(rkey).Should(Equal(key))
+ Expect(rvalue).Should(Equal(value), "Value for key %q (%q)", key_, key)
+ })
+}
+
+func TestFindAfterLast(db Find, kv KeyValue) {
+ var key []byte
+ if kv.Len() > 0 {
+ key_, _ := kv.Index(kv.Len() - 1)
+ key = BytesAfter(key_)
+ }
+ rkey, _, err := db.TestFind(key)
+ Expect(err).Should(HaveOccurred(), "Find for key %q yield key %q", key, rkey)
+ Expect(err).Should(Equal(errors.ErrNotFound))
+}
+
+func TestGet(db Get, kv KeyValue) {
+ ShuffledIndex(nil, kv.Len(), 1, func(i int) {
+ key_, key, value := kv.IndexInexact(i)
+
+ // Using exact key.
+ rvalue, err := db.TestGet(key)
+ Expect(err).ShouldNot(HaveOccurred(), "Error for key %q", key)
+ Expect(rvalue).Should(Equal(value), "Value for key %q", key)
+
+ // Using inexact key.
+ if len(key_) > 0 {
+ _, err = db.TestGet(key_)
+ Expect(err).Should(HaveOccurred(), "Error for key %q", key_)
+ Expect(err).Should(Equal(errors.ErrNotFound))
+ }
+ })
+}
+
+func TestHas(db Has, kv KeyValue) {
+ ShuffledIndex(nil, kv.Len(), 1, func(i int) {
+ key_, key, _ := kv.IndexInexact(i)
+
+ // Using exact key.
+ ret, err := db.TestHas(key)
+ Expect(err).ShouldNot(HaveOccurred(), "Error for key %q", key)
+ Expect(ret).Should(BeTrue(), "False for key %q", key)
+
+ // Using inexact key.
+ if len(key_) > 0 {
+ ret, err = db.TestHas(key_)
+ Expect(err).ShouldNot(HaveOccurred(), "Error for key %q", key_)
+ Expect(ret).ShouldNot(BeTrue(), "True for key %q", key)
+ }
+ })
+}
+
+func TestIter(db NewIterator, r *util.Range, kv KeyValue) {
+ iter := db.TestNewIterator(r)
+ Expect(iter.Error()).ShouldNot(HaveOccurred())
+
+ t := IteratorTesting{
+ KeyValue: kv,
+ Iter: iter,
+ }
+
+ DoIteratorTesting(&t)
+ iter.Release()
+}
+
func KeyValueTesting(rnd *rand.Rand, kv KeyValue, p DB, setup func(KeyValue) DB, teardown func(DB)) {
if rnd == nil {
rnd = NewRand()
@@ -35,122 +113,68 @@ func KeyValueTesting(rnd *rand.Rand, kv KeyValue, p DB, setup func(KeyValue) DB,
It("Should find all keys with Find", func() {
if db, ok := p.(Find); ok {
- ShuffledIndex(nil, kv.Len(), 1, func(i int) {
- key_, key, value := kv.IndexInexact(i)
-
- // Using exact key.
- rkey, rvalue, err := db.TestFind(key)
- Expect(err).ShouldNot(HaveOccurred(), "Error for key %q", key)
- Expect(rkey).Should(Equal(key), "Key")
- Expect(rvalue).Should(Equal(value), "Value for key %q", key)
-
- // Using inexact key.
- rkey, rvalue, err = db.TestFind(key_)
- Expect(err).ShouldNot(HaveOccurred(), "Error for key %q (%q)", key_, key)
- Expect(rkey).Should(Equal(key))
- Expect(rvalue).Should(Equal(value), "Value for key %q (%q)", key_, key)
- })
+ TestFind(db, kv)
}
})
- It("Should return error if the key is not present", func() {
+ It("Should return error if Find on key after the last", func() {
if db, ok := p.(Find); ok {
- var key []byte
- if kv.Len() > 0 {
- key_, _ := kv.Index(kv.Len() - 1)
- key = BytesAfter(key_)
- }
- rkey, _, err := db.TestFind(key)
- Expect(err).Should(HaveOccurred(), "Find for key %q yield key %q", key, rkey)
- Expect(err).Should(Equal(errors.ErrNotFound))
+ TestFindAfterLast(db, kv)
}
})
It("Should only find exact key with Get", func() {
if db, ok := p.(Get); ok {
- ShuffledIndex(nil, kv.Len(), 1, func(i int) {
- key_, key, value := kv.IndexInexact(i)
-
- // Using exact key.
- rvalue, err := db.TestGet(key)
- Expect(err).ShouldNot(HaveOccurred(), "Error for key %q", key)
- Expect(rvalue).Should(Equal(value), "Value for key %q", key)
-
- // Using inexact key.
- if len(key_) > 0 {
- _, err = db.TestGet(key_)
- Expect(err).Should(HaveOccurred(), "Error for key %q", key_)
- Expect(err).Should(Equal(errors.ErrNotFound))
- }
- })
+ TestGet(db, kv)
}
})
It("Should only find present key with Has", func() {
if db, ok := p.(Has); ok {
- ShuffledIndex(nil, kv.Len(), 1, func(i int) {
- key_, key, _ := kv.IndexInexact(i)
-
- // Using exact key.
- ret, err := db.TestHas(key)
- Expect(err).ShouldNot(HaveOccurred(), "Error for key %q", key)
- Expect(ret).Should(BeTrue(), "False for key %q", key)
-
- // Using inexact key.
- if len(key_) > 0 {
- ret, err = db.TestHas(key_)
- Expect(err).ShouldNot(HaveOccurred(), "Error for key %q", key_)
- Expect(ret).ShouldNot(BeTrue(), "True for key %q", key)
- }
- })
+ TestHas(db, kv)
}
})
- TestIter := func(r *util.Range, _kv KeyValue) {
+ It("Should iterates and seeks correctly", func(done Done) {
if db, ok := p.(NewIterator); ok {
- iter := db.TestNewIterator(r)
- Expect(iter.Error()).ShouldNot(HaveOccurred())
-
- t := IteratorTesting{
- KeyValue: _kv,
- Iter: iter,
- }
-
- DoIteratorTesting(&t)
- iter.Release()
+ TestIter(db, nil, kv.Clone())
}
- }
-
- It("Should iterates and seeks correctly", func(done Done) {
- TestIter(nil, kv.Clone())
done <- true
}, 3.0)
- RandomIndex(rnd, kv.Len(), Min(kv.Len(), 50), func(i int) {
- type slice struct {
- r *util.Range
- start, limit int
- }
+ It("Should iterates and seeks slice correctly", func(done Done) {
+ if db, ok := p.(NewIterator); ok {
+ RandomIndex(rnd, kv.Len(), Min(kv.Len(), 50), func(i int) {
+ type slice struct {
+ r *util.Range
+ start, limit int
+ }
- key_, _, _ := kv.IndexInexact(i)
- for _, x := range []slice{
- {&util.Range{Start: key_, Limit: nil}, i, kv.Len()},
- {&util.Range{Start: nil, Limit: key_}, 0, i},
- } {
- It(fmt.Sprintf("Should iterates and seeks correctly of a slice %d .. %d", x.start, x.limit), func(done Done) {
- TestIter(x.r, kv.Slice(x.start, x.limit))
- done <- true
- }, 3.0)
+ key_, _, _ := kv.IndexInexact(i)
+ for _, x := range []slice{
+ {&util.Range{Start: key_, Limit: nil}, i, kv.Len()},
+ {&util.Range{Start: nil, Limit: key_}, 0, i},
+ } {
+ By(fmt.Sprintf("Random index of %d .. %d", x.start, x.limit), func() {
+ TestIter(db, x.r, kv.Slice(x.start, x.limit))
+ })
+ }
+ })
}
- })
+ done <- true
+ }, 50.0)
- RandomRange(rnd, kv.Len(), Min(kv.Len(), 50), func(start, limit int) {
- It(fmt.Sprintf("Should iterates and seeks correctly of a slice %d .. %d", start, limit), func(done Done) {
- r := kv.Range(start, limit)
- TestIter(&r, kv.Slice(start, limit))
- done <- true
- }, 3.0)
- })
+ It("Should iterates and seeks slice correctly", func(done Done) {
+ if db, ok := p.(NewIterator); ok {
+ RandomRange(rnd, kv.Len(), Min(kv.Len(), 50), func(start, limit int) {
+ By(fmt.Sprintf("Random range of %d .. %d", start, limit), func() {
+ r := kv.Range(start, limit)
+ TestIter(db, &r, kv.Slice(start, limit))
+ })
+ })
+ }
+ done <- true
+ }, 50.0)
}
func AllKeyValueTesting(rnd *rand.Rand, body, setup func(KeyValue) DB, teardown func(DB)) {
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/storage.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/storage.go
index 59c496d54..1d9163ea4 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/storage.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil/storage.go
@@ -10,6 +10,7 @@ import (
"bytes"
"fmt"
"io"
+ "math/rand"
"os"
"path/filepath"
"runtime"
@@ -24,8 +25,8 @@ import (
var (
storageMu sync.Mutex
- storageUseFS bool = true
- storageKeepFS bool = false
+ storageUseFS = true
+ storageKeepFS = false
storageNum int
)
@@ -35,6 +36,7 @@ const (
ModeOpen StorageMode = 1 << iota
ModeCreate
ModeRemove
+ ModeRename
ModeRead
ModeWrite
ModeSync
@@ -45,6 +47,7 @@ const (
modeOpen = iota
modeCreate
modeRemove
+ modeRename
modeRead
modeWrite
modeSync
@@ -73,6 +76,8 @@ func flattenType(m StorageMode, t storage.FileType) int {
x = modeCreate
case ModeRemove:
x = modeRemove
+ case ModeRename:
+ x = modeRename
case ModeRead:
x = modeRead
case ModeWrite:
@@ -121,6 +126,8 @@ func listFlattenType(m StorageMode, t storage.FileType) []int {
add(modeCreate)
case m&ModeRemove != 0:
add(modeRemove)
+ case m&ModeRename != 0:
+ add(modeRename)
case m&ModeRead != 0:
add(modeRead)
case m&ModeWrite != 0:
@@ -133,15 +140,15 @@ func listFlattenType(m StorageMode, t storage.FileType) []int {
return ret
}
-func packFile(num uint64, t storage.FileType) uint64 {
- if num>>(64-typeCount) != 0 {
+func packFile(fd storage.FileDesc) uint64 {
+ if fd.Num>>(63-typeCount) != 0 {
panic("overflow")
}
- return num<<typeCount | uint64(t)
+ return uint64(fd.Num<<typeCount) | uint64(fd.Type)
}
-func unpackFile(x uint64) (uint64, storage.FileType) {
- return x >> typeCount, storage.FileType(x) & storage.TypeAll
+func unpackFile(x uint64) storage.FileDesc {
+ return storage.FileDesc{storage.FileType(x) & storage.TypeAll, int64(x >> typeCount)}
}
type emulatedError struct {
@@ -163,189 +170,98 @@ func (l storageLock) Release() {
}
type reader struct {
- f *file
+ s *Storage
+ fd storage.FileDesc
storage.Reader
}
func (r *reader) Read(p []byte) (n int, err error) {
- err = r.f.s.emulateError(ModeRead, r.f.Type())
+ err = r.s.emulateError(ModeRead, r.fd.Type)
if err == nil {
- r.f.s.stall(ModeRead, r.f.Type())
+ r.s.stall(ModeRead, r.fd.Type)
n, err = r.Reader.Read(p)
}
- r.f.s.count(ModeRead, r.f.Type(), n)
+ r.s.count(ModeRead, r.fd.Type, n)
if err != nil && err != io.EOF {
- r.f.s.logI("read error, num=%d type=%v n=%d err=%v", r.f.Num(), r.f.Type(), n, err)
+ r.s.logI("read error, fd=%s n=%d err=%v", r.fd, n, err)
}
return
}
func (r *reader) ReadAt(p []byte, off int64) (n int, err error) {
- err = r.f.s.emulateError(ModeRead, r.f.Type())
+ err = r.s.emulateError(ModeRead, r.fd.Type)
if err == nil {
- r.f.s.stall(ModeRead, r.f.Type())
+ r.s.stall(ModeRead, r.fd.Type)
n, err = r.Reader.ReadAt(p, off)
}
- r.f.s.count(ModeRead, r.f.Type(), n)
+ r.s.count(ModeRead, r.fd.Type, n)
if err != nil && err != io.EOF {
- r.f.s.logI("readAt error, num=%d type=%v offset=%d n=%d err=%v", r.f.Num(), r.f.Type(), off, n, err)
+ r.s.logI("readAt error, fd=%s offset=%d n=%d err=%v", r.fd, off, n, err)
}
return
}
func (r *reader) Close() (err error) {
- return r.f.doClose(r.Reader)
+ return r.s.fileClose(r.fd, r.Reader)
}
type writer struct {
- f *file
+ s *Storage
+ fd storage.FileDesc
storage.Writer
}
func (w *writer) Write(p []byte) (n int, err error) {
- err = w.f.s.emulateError(ModeWrite, w.f.Type())
+ err = w.s.emulateError(ModeWrite, w.fd.Type)
if err == nil {
- w.f.s.stall(ModeWrite, w.f.Type())
+ w.s.stall(ModeWrite, w.fd.Type)
n, err = w.Writer.Write(p)
}
- w.f.s.count(ModeWrite, w.f.Type(), n)
+ w.s.count(ModeWrite, w.fd.Type, n)
if err != nil && err != io.EOF {
- w.f.s.logI("write error, num=%d type=%v n=%d err=%v", w.f.Num(), w.f.Type(), n, err)
+ w.s.logI("write error, fd=%s n=%d err=%v", w.fd, n, err)
}
return
}
func (w *writer) Sync() (err error) {
- err = w.f.s.emulateError(ModeSync, w.f.Type())
+ err = w.s.emulateError(ModeSync, w.fd.Type)
if err == nil {
- w.f.s.stall(ModeSync, w.f.Type())
+ w.s.stall(ModeSync, w.fd.Type)
err = w.Writer.Sync()
}
- w.f.s.count(ModeSync, w.f.Type(), 0)
+ w.s.count(ModeSync, w.fd.Type, 0)
if err != nil {
- w.f.s.logI("sync error, num=%d type=%v err=%v", w.f.Num(), w.f.Type(), err)
+ w.s.logI("sync error, fd=%s err=%v", w.fd, err)
}
return
}
func (w *writer) Close() (err error) {
- return w.f.doClose(w.Writer)
-}
-
-type file struct {
- s *Storage
- storage.File
-}
-
-func (f *file) pack() uint64 {
- return packFile(f.Num(), f.Type())
-}
-
-func (f *file) assertOpen() {
- ExpectWithOffset(2, f.s.opens).NotTo(HaveKey(f.pack()), "File open, num=%d type=%v writer=%v", f.Num(), f.Type(), f.s.opens[f.pack()])
-}
-
-func (f *file) doClose(closer io.Closer) (err error) {
- err = f.s.emulateError(ModeClose, f.Type())
- if err == nil {
- f.s.stall(ModeClose, f.Type())
- }
- f.s.mu.Lock()
- defer f.s.mu.Unlock()
- if err == nil {
- ExpectWithOffset(2, f.s.opens).To(HaveKey(f.pack()), "File closed, num=%d type=%v", f.Num(), f.Type())
- err = closer.Close()
- }
- f.s.countNB(ModeClose, f.Type(), 0)
- writer := f.s.opens[f.pack()]
- if err != nil {
- f.s.logISkip(1, "file close failed, num=%d type=%v writer=%v err=%v", f.Num(), f.Type(), writer, err)
- } else {
- f.s.logISkip(1, "file closed, num=%d type=%v writer=%v", f.Num(), f.Type(), writer)
- delete(f.s.opens, f.pack())
- }
- return
-}
-
-func (f *file) Open() (r storage.Reader, err error) {
- err = f.s.emulateError(ModeOpen, f.Type())
- if err == nil {
- f.s.stall(ModeOpen, f.Type())
- }
- f.s.mu.Lock()
- defer f.s.mu.Unlock()
- if err == nil {
- f.assertOpen()
- f.s.countNB(ModeOpen, f.Type(), 0)
- r, err = f.File.Open()
- }
- if err != nil {
- f.s.logI("file open failed, num=%d type=%v err=%v", f.Num(), f.Type(), err)
- } else {
- f.s.logI("file opened, num=%d type=%v", f.Num(), f.Type())
- f.s.opens[f.pack()] = false
- r = &reader{f, r}
- }
- return
-}
-
-func (f *file) Create() (w storage.Writer, err error) {
- err = f.s.emulateError(ModeCreate, f.Type())
- if err == nil {
- f.s.stall(ModeCreate, f.Type())
- }
- f.s.mu.Lock()
- defer f.s.mu.Unlock()
- if err == nil {
- f.assertOpen()
- f.s.countNB(ModeCreate, f.Type(), 0)
- w, err = f.File.Create()
- }
- if err != nil {
- f.s.logI("file create failed, num=%d type=%v err=%v", f.Num(), f.Type(), err)
- } else {
- f.s.logI("file created, num=%d type=%v", f.Num(), f.Type())
- f.s.opens[f.pack()] = true
- w = &writer{f, w}
- }
- return
-}
-
-func (f *file) Remove() (err error) {
- err = f.s.emulateError(ModeRemove, f.Type())
- if err == nil {
- f.s.stall(ModeRemove, f.Type())
- }
- f.s.mu.Lock()
- defer f.s.mu.Unlock()
- if err == nil {
- f.assertOpen()
- f.s.countNB(ModeRemove, f.Type(), 0)
- err = f.File.Remove()
- }
- if err != nil {
- f.s.logI("file remove failed, num=%d type=%v err=%v", f.Num(), f.Type(), err)
- } else {
- f.s.logI("file removed, num=%d type=%v", f.Num(), f.Type())
- }
- return
+ return w.s.fileClose(w.fd, w.Writer)
}
type Storage struct {
storage.Storage
- closeFn func() error
+ path string
+ onClose func() (preserve bool, err error)
+ onLog func(str string)
lmu sync.Mutex
lb bytes.Buffer
- mu sync.Mutex
+ mu sync.Mutex
+ rand *rand.Rand
// Open files, true=writer, false=reader
- opens map[uint64]bool
- counters [flattenCount]int
- bytesCounter [flattenCount]int64
- emulatedError [flattenCount]error
- stallCond sync.Cond
- stalled [flattenCount]bool
+ opens map[uint64]bool
+ counters [flattenCount]int
+ bytesCounter [flattenCount]int64
+ emulatedError [flattenCount]error
+ emulatedErrorOnce [flattenCount]bool
+ emulatedRandomError [flattenCount]error
+ emulatedRandomErrorProb [flattenCount]float64
+ stallCond sync.Cond
+ stalled [flattenCount]bool
}
func (s *Storage) log(skip int, str string) {
@@ -374,7 +290,12 @@ func (s *Storage) log(skip int, str string) {
}
s.lb.WriteString(line)
}
- s.lb.WriteByte('\n')
+ if s.onLog != nil {
+ s.onLog(s.lb.String())
+ s.lb.Reset()
+ } else {
+ s.lb.WriteByte('\n')
+ }
}
func (s *Storage) logISkip(skip int, format string, args ...interface{}) {
@@ -395,74 +316,220 @@ func (s *Storage) logI(format string, args ...interface{}) {
s.logISkip(1, format, args...)
}
+func (s *Storage) OnLog(onLog func(log string)) {
+ s.lmu.Lock()
+ s.onLog = onLog
+ if s.lb.Len() != 0 {
+ log := s.lb.String()
+ s.onLog(log[:len(log)-1])
+ s.lb.Reset()
+ }
+ s.lmu.Unlock()
+}
+
func (s *Storage) Log(str string) {
s.log(1, "Log: "+str)
s.Storage.Log(str)
}
-func (s *Storage) Lock() (r util.Releaser, err error) {
- r, err = s.Storage.Lock()
+func (s *Storage) Lock() (l storage.Lock, err error) {
+ l, err = s.Storage.Lock()
if err != nil {
s.logI("storage locking failed, err=%v", err)
} else {
s.logI("storage locked")
- r = storageLock{s, r}
+ l = storageLock{s, l}
}
return
}
-func (s *Storage) GetFile(num uint64, t storage.FileType) storage.File {
- return &file{s, s.Storage.GetFile(num, t)}
-}
-
-func (s *Storage) GetFiles(t storage.FileType) (files []storage.File, err error) {
- rfiles, err := s.Storage.GetFiles(t)
+func (s *Storage) List(t storage.FileType) (fds []storage.FileDesc, err error) {
+ fds, err = s.Storage.List(t)
if err != nil {
- s.logI("get files failed, err=%v", err)
+ s.logI("list failed, err=%v", err)
return
}
- files = make([]storage.File, len(rfiles))
- for i, f := range rfiles {
- files[i] = &file{s, f}
- }
- s.logI("get files, type=0x%x count=%d", int(t), len(files))
+ s.logI("list, type=0x%x count=%d", int(t), len(fds))
return
}
-func (s *Storage) GetManifest() (f storage.File, err error) {
- manifest, err := s.Storage.GetManifest()
+func (s *Storage) GetMeta() (fd storage.FileDesc, err error) {
+ fd, err = s.Storage.GetMeta()
if err != nil {
if !os.IsNotExist(err) {
- s.logI("get manifest failed, err=%v", err)
+ s.logI("get meta failed, err=%v", err)
}
return
}
- s.logI("get manifest, num=%d", manifest.Num())
- return &file{s, manifest}, nil
+ s.logI("get meta, fd=%s", fd)
+ return
}
-func (s *Storage) SetManifest(f storage.File) error {
- f_, ok := f.(*file)
- ExpectWithOffset(1, ok).To(BeTrue())
- ExpectWithOffset(1, f_.Type()).To(Equal(storage.TypeManifest))
- err := s.Storage.SetManifest(f_.File)
+func (s *Storage) SetMeta(fd storage.FileDesc) error {
+ ExpectWithOffset(1, fd.Type).To(Equal(storage.TypeManifest))
+ err := s.Storage.SetMeta(fd)
if err != nil {
- s.logI("set manifest failed, err=%v", err)
+ s.logI("set meta failed, fd=%s err=%v", fd, err)
} else {
- s.logI("set manifest, num=%d", f_.Num())
+ s.logI("set meta, fd=%s", fd)
}
return err
}
+func (s *Storage) fileClose(fd storage.FileDesc, closer io.Closer) (err error) {
+ err = s.emulateError(ModeClose, fd.Type)
+ if err == nil {
+ s.stall(ModeClose, fd.Type)
+ }
+ x := packFile(fd)
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ if err == nil {
+ ExpectWithOffset(2, s.opens).To(HaveKey(x), "File closed, fd=%s", fd)
+ err = closer.Close()
+ }
+ s.countNB(ModeClose, fd.Type, 0)
+ writer := s.opens[x]
+ if err != nil {
+ s.logISkip(1, "file close failed, fd=%s writer=%v err=%v", fd, writer, err)
+ } else {
+ s.logISkip(1, "file closed, fd=%s writer=%v", fd, writer)
+ delete(s.opens, x)
+ }
+ return
+}
+
+func (s *Storage) assertOpen(fd storage.FileDesc) {
+ x := packFile(fd)
+ ExpectWithOffset(2, s.opens).NotTo(HaveKey(x), "File open, fd=%s writer=%v", fd, s.opens[x])
+}
+
+func (s *Storage) Open(fd storage.FileDesc) (r storage.Reader, err error) {
+ err = s.emulateError(ModeOpen, fd.Type)
+ if err == nil {
+ s.stall(ModeOpen, fd.Type)
+ }
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ if err == nil {
+ s.assertOpen(fd)
+ s.countNB(ModeOpen, fd.Type, 0)
+ r, err = s.Storage.Open(fd)
+ }
+ if err != nil {
+ s.logI("file open failed, fd=%s err=%v", fd, err)
+ } else {
+ s.logI("file opened, fd=%s", fd)
+ s.opens[packFile(fd)] = false
+ r = &reader{s, fd, r}
+ }
+ return
+}
+
+func (s *Storage) Create(fd storage.FileDesc) (w storage.Writer, err error) {
+ err = s.emulateError(ModeCreate, fd.Type)
+ if err == nil {
+ s.stall(ModeCreate, fd.Type)
+ }
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ if err == nil {
+ s.assertOpen(fd)
+ s.countNB(ModeCreate, fd.Type, 0)
+ w, err = s.Storage.Create(fd)
+ }
+ if err != nil {
+ s.logI("file create failed, fd=%s err=%v", fd, err)
+ } else {
+ s.logI("file created, fd=%s", fd)
+ s.opens[packFile(fd)] = true
+ w = &writer{s, fd, w}
+ }
+ return
+}
+
+func (s *Storage) Remove(fd storage.FileDesc) (err error) {
+ err = s.emulateError(ModeRemove, fd.Type)
+ if err == nil {
+ s.stall(ModeRemove, fd.Type)
+ }
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ if err == nil {
+ s.assertOpen(fd)
+ s.countNB(ModeRemove, fd.Type, 0)
+ err = s.Storage.Remove(fd)
+ }
+ if err != nil {
+ s.logI("file remove failed, fd=%s err=%v", fd, err)
+ } else {
+ s.logI("file removed, fd=%s", fd)
+ }
+ return
+}
+
+func (s *Storage) ForceRemove(fd storage.FileDesc) (err error) {
+ s.countNB(ModeRemove, fd.Type, 0)
+ if err = s.Storage.Remove(fd); err != nil {
+ s.logI("file remove failed (forced), fd=%s err=%v", fd, err)
+ } else {
+ s.logI("file removed (forced), fd=%s", fd)
+ }
+ return
+}
+
+func (s *Storage) Rename(oldfd, newfd storage.FileDesc) (err error) {
+ err = s.emulateError(ModeRename, oldfd.Type)
+ if err == nil {
+ s.stall(ModeRename, oldfd.Type)
+ }
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ if err == nil {
+ s.assertOpen(oldfd)
+ s.assertOpen(newfd)
+ s.countNB(ModeRename, oldfd.Type, 0)
+ err = s.Storage.Rename(oldfd, newfd)
+ }
+ if err != nil {
+ s.logI("file rename failed, oldfd=%s newfd=%s err=%v", oldfd, newfd, err)
+ } else {
+ s.logI("file renamed, oldfd=%s newfd=%s", oldfd, newfd)
+ }
+ return
+}
+
+func (s *Storage) ForceRename(oldfd, newfd storage.FileDesc) (err error) {
+ s.countNB(ModeRename, oldfd.Type, 0)
+ if err = s.Storage.Rename(oldfd, newfd); err != nil {
+ s.logI("file rename failed (forced), oldfd=%s newfd=%s err=%v", oldfd, newfd, err)
+ } else {
+ s.logI("file renamed (forced), oldfd=%s newfd=%s", oldfd, newfd)
+ }
+ return
+}
+
func (s *Storage) openFiles() string {
out := "Open files:"
for x, writer := range s.opens {
- num, t := unpackFile(x)
- out += fmt.Sprintf("\n · num=%d type=%v writer=%v", num, t, writer)
+ fd := unpackFile(x)
+ out += fmt.Sprintf("\n · fd=%s writer=%v", fd, writer)
}
return out
}
+func (s *Storage) CloseCheck() {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ ExpectWithOffset(1, s.opens).To(BeEmpty(), s.openFiles())
+}
+
+func (s *Storage) OnClose(onClose func() (preserve bool, err error)) {
+ s.mu.Lock()
+ s.onClose = onClose
+ s.mu.Unlock()
+}
+
func (s *Storage) Close() error {
s.mu.Lock()
defer s.mu.Unlock()
@@ -473,9 +540,22 @@ func (s *Storage) Close() error {
} else {
s.logI("storage closed")
}
- if s.closeFn != nil {
- if err1 := s.closeFn(); err1 != nil {
- s.logI("close func error, err=%v", err1)
+ var preserve bool
+ if s.onClose != nil {
+ var err0 error
+ if preserve, err0 = s.onClose(); err0 != nil {
+ s.logI("onClose error, err=%v", err0)
+ }
+ }
+ if s.path != "" {
+ if storageKeepFS || preserve {
+ s.logI("storage is preserved, path=%v", s.path)
+ } else {
+ if err1 := os.RemoveAll(s.path); err1 != nil {
+ s.logI("cannot remove storage, err=%v", err1)
+ } else {
+ s.logI("storage has been removed")
+ }
}
}
return err
@@ -510,8 +590,14 @@ func (s *Storage) Counter(m StorageMode, t storage.FileType) (count int, bytes i
func (s *Storage) emulateError(m StorageMode, t storage.FileType) error {
s.mu.Lock()
defer s.mu.Unlock()
- err := s.emulatedError[flattenType(m, t)]
- if err != nil {
+ x := flattenType(m, t)
+ if err := s.emulatedError[x]; err != nil {
+ if s.emulatedErrorOnce[x] {
+ s.emulatedError[x] = nil
+ }
+ return emulatedError{err}
+ }
+ if err := s.emulatedRandomError[x]; err != nil && s.rand.Float64() < s.emulatedRandomErrorProb[x] {
return emulatedError{err}
}
return nil
@@ -522,6 +608,25 @@ func (s *Storage) EmulateError(m StorageMode, t storage.FileType, err error) {
defer s.mu.Unlock()
for _, x := range listFlattenType(m, t) {
s.emulatedError[x] = err
+ s.emulatedErrorOnce[x] = false
+ }
+}
+
+func (s *Storage) EmulateErrorOnce(m StorageMode, t storage.FileType, err error) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ for _, x := range listFlattenType(m, t) {
+ s.emulatedError[x] = err
+ s.emulatedErrorOnce[x] = true
+ }
+}
+
+func (s *Storage) EmulateRandomError(m StorageMode, t storage.FileType, prob float64, err error) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ for _, x := range listFlattenType(m, t) {
+ s.emulatedRandomError[x] = err
+ s.emulatedRandomErrorProb[x] = prob
}
}
@@ -552,24 +657,20 @@ func (s *Storage) Release(m StorageMode, t storage.FileType) {
}
func NewStorage() *Storage {
- var stor storage.Storage
- var closeFn func() error
+ var (
+ stor storage.Storage
+ path string
+ )
if storageUseFS {
for {
storageMu.Lock()
num := storageNum
storageNum++
storageMu.Unlock()
- path := filepath.Join(os.TempDir(), fmt.Sprintf("goleveldb-test%d0%d0%d", os.Getuid(), os.Getpid(), num))
+ path = filepath.Join(os.TempDir(), fmt.Sprintf("goleveldb-test%d0%d0%d", os.Getuid(), os.Getpid(), num))
if _, err := os.Stat(path); os.IsNotExist(err) {
- stor, err = storage.OpenFile(path)
+ stor, err = storage.OpenFile(path, false)
ExpectWithOffset(1, err).NotTo(HaveOccurred(), "creating storage at %s", path)
- closeFn = func() error {
- if storageKeepFS {
- return nil
- }
- return os.RemoveAll(path)
- }
break
}
}
@@ -578,9 +679,16 @@ func NewStorage() *Storage {
}
s := &Storage{
Storage: stor,
- closeFn: closeFn,
+ path: path,
+ rand: NewRand(),
opens: make(map[uint64]bool),
}
s.stallCond.L = &s.mu
+ if s.path != "" {
+ s.logI("using FS storage")
+ s.logI("storage path: %s", s.path)
+ } else {
+ s.logI("using MEM storage")
+ }
return s
}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil_test.go
deleted file mode 100644
index 25bf2b29f..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/testutil_test.go
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (c) 2014, Suryandaru Triandana <syndtr@gmail.com>
-// All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package leveldb
-
-import (
- . "github.com/onsi/gomega"
-
- "github.com/syndtr/goleveldb/leveldb/iterator"
- "github.com/syndtr/goleveldb/leveldb/opt"
- "github.com/syndtr/goleveldb/leveldb/testutil"
- "github.com/syndtr/goleveldb/leveldb/util"
-)
-
-type testingDB struct {
- *DB
- ro *opt.ReadOptions
- wo *opt.WriteOptions
- stor *testutil.Storage
-}
-
-func (t *testingDB) TestPut(key []byte, value []byte) error {
- return t.Put(key, value, t.wo)
-}
-
-func (t *testingDB) TestDelete(key []byte) error {
- return t.Delete(key, t.wo)
-}
-
-func (t *testingDB) TestGet(key []byte) (value []byte, err error) {
- return t.Get(key, t.ro)
-}
-
-func (t *testingDB) TestHas(key []byte) (ret bool, err error) {
- return t.Has(key, t.ro)
-}
-
-func (t *testingDB) TestNewIterator(slice *util.Range) iterator.Iterator {
- return t.NewIterator(slice, t.ro)
-}
-
-func (t *testingDB) TestClose() {
- err := t.Close()
- ExpectWithOffset(1, err).NotTo(HaveOccurred())
- err = t.stor.Close()
- ExpectWithOffset(1, err).NotTo(HaveOccurred())
-}
-
-func newTestingDB(o *opt.Options, ro *opt.ReadOptions, wo *opt.WriteOptions) *testingDB {
- stor := testutil.NewStorage()
- db, err := Open(stor, o)
- // FIXME: This may be called from outside It, which may cause panic.
- Expect(err).NotTo(HaveOccurred())
- return &testingDB{
- DB: db,
- ro: ro,
- wo: wo,
- stor: stor,
- }
-}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util.go
index 1a5bf71a3..3b663d1cc 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util.go
@@ -72,20 +72,20 @@ func maxInt(a, b int) int {
return b
}
-type files []storage.File
+type fdSorter []storage.FileDesc
-func (p files) Len() int {
+func (p fdSorter) Len() int {
return len(p)
}
-func (p files) Less(i, j int) bool {
- return p[i].Num() < p[j].Num()
+func (p fdSorter) Less(i, j int) bool {
+ return p[i].Num < p[j].Num
}
-func (p files) Swap(i, j int) {
+func (p fdSorter) Swap(i, j int) {
p[i], p[j] = p[j], p[i]
}
-func (p files) sort() {
- sort.Sort(p)
+func sortFds(fds []storage.FileDesc) {
+ sort.Sort(fdSorter(fds))
}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/buffer_pool.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/buffer_pool.go
index 2b8453d75..2f3db974a 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/buffer_pool.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/buffer_pool.go
@@ -201,6 +201,7 @@ func (p *BufferPool) String() string {
func (p *BufferPool) drain() {
ticker := time.NewTicker(2 * time.Second)
+ defer ticker.Stop()
for {
select {
case <-ticker.C:
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/buffer_test.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/buffer_test.go
deleted file mode 100644
index 87d96739c..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/util/buffer_test.go
+++ /dev/null
@@ -1,369 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package util
-
-import (
- "bytes"
- "io"
- "math/rand"
- "runtime"
- "testing"
-)
-
-const N = 10000 // make this bigger for a larger (and slower) test
-var data string // test data for write tests
-var testBytes []byte // test data; same as data but as a slice.
-
-func init() {
- testBytes = make([]byte, N)
- for i := 0; i < N; i++ {
- testBytes[i] = 'a' + byte(i%26)
- }
- data = string(testBytes)
-}
-
-// Verify that contents of buf match the string s.
-func check(t *testing.T, testname string, buf *Buffer, s string) {
- bytes := buf.Bytes()
- str := buf.String()
- if buf.Len() != len(bytes) {
- t.Errorf("%s: buf.Len() == %d, len(buf.Bytes()) == %d", testname, buf.Len(), len(bytes))
- }
-
- if buf.Len() != len(str) {
- t.Errorf("%s: buf.Len() == %d, len(buf.String()) == %d", testname, buf.Len(), len(str))
- }
-
- if buf.Len() != len(s) {
- t.Errorf("%s: buf.Len() == %d, len(s) == %d", testname, buf.Len(), len(s))
- }
-
- if string(bytes) != s {
- t.Errorf("%s: string(buf.Bytes()) == %q, s == %q", testname, string(bytes), s)
- }
-}
-
-// Fill buf through n writes of byte slice fub.
-// The initial contents of buf corresponds to the string s;
-// the result is the final contents of buf returned as a string.
-func fillBytes(t *testing.T, testname string, buf *Buffer, s string, n int, fub []byte) string {
- check(t, testname+" (fill 1)", buf, s)
- for ; n > 0; n-- {
- m, err := buf.Write(fub)
- if m != len(fub) {
- t.Errorf(testname+" (fill 2): m == %d, expected %d", m, len(fub))
- }
- if err != nil {
- t.Errorf(testname+" (fill 3): err should always be nil, found err == %s", err)
- }
- s += string(fub)
- check(t, testname+" (fill 4)", buf, s)
- }
- return s
-}
-
-func TestNewBuffer(t *testing.T) {
- buf := NewBuffer(testBytes)
- check(t, "NewBuffer", buf, data)
-}
-
-// Empty buf through repeated reads into fub.
-// The initial contents of buf corresponds to the string s.
-func empty(t *testing.T, testname string, buf *Buffer, s string, fub []byte) {
- check(t, testname+" (empty 1)", buf, s)
-
- for {
- n, err := buf.Read(fub)
- if n == 0 {
- break
- }
- if err != nil {
- t.Errorf(testname+" (empty 2): err should always be nil, found err == %s", err)
- }
- s = s[n:]
- check(t, testname+" (empty 3)", buf, s)
- }
-
- check(t, testname+" (empty 4)", buf, "")
-}
-
-func TestBasicOperations(t *testing.T) {
- var buf Buffer
-
- for i := 0; i < 5; i++ {
- check(t, "TestBasicOperations (1)", &buf, "")
-
- buf.Reset()
- check(t, "TestBasicOperations (2)", &buf, "")
-
- buf.Truncate(0)
- check(t, "TestBasicOperations (3)", &buf, "")
-
- n, err := buf.Write([]byte(data[0:1]))
- if n != 1 {
- t.Errorf("wrote 1 byte, but n == %d", n)
- }
- if err != nil {
- t.Errorf("err should always be nil, but err == %s", err)
- }
- check(t, "TestBasicOperations (4)", &buf, "a")
-
- buf.WriteByte(data[1])
- check(t, "TestBasicOperations (5)", &buf, "ab")
-
- n, err = buf.Write([]byte(data[2:26]))
- if n != 24 {
- t.Errorf("wrote 25 bytes, but n == %d", n)
- }
- check(t, "TestBasicOperations (6)", &buf, string(data[0:26]))
-
- buf.Truncate(26)
- check(t, "TestBasicOperations (7)", &buf, string(data[0:26]))
-
- buf.Truncate(20)
- check(t, "TestBasicOperations (8)", &buf, string(data[0:20]))
-
- empty(t, "TestBasicOperations (9)", &buf, string(data[0:20]), make([]byte, 5))
- empty(t, "TestBasicOperations (10)", &buf, "", make([]byte, 100))
-
- buf.WriteByte(data[1])
- c, err := buf.ReadByte()
- if err != nil {
- t.Error("ReadByte unexpected eof")
- }
- if c != data[1] {
- t.Errorf("ReadByte wrong value c=%v", c)
- }
- c, err = buf.ReadByte()
- if err == nil {
- t.Error("ReadByte unexpected not eof")
- }
- }
-}
-
-func TestLargeByteWrites(t *testing.T) {
- var buf Buffer
- limit := 30
- if testing.Short() {
- limit = 9
- }
- for i := 3; i < limit; i += 3 {
- s := fillBytes(t, "TestLargeWrites (1)", &buf, "", 5, testBytes)
- empty(t, "TestLargeByteWrites (2)", &buf, s, make([]byte, len(data)/i))
- }
- check(t, "TestLargeByteWrites (3)", &buf, "")
-}
-
-func TestLargeByteReads(t *testing.T) {
- var buf Buffer
- for i := 3; i < 30; i += 3 {
- s := fillBytes(t, "TestLargeReads (1)", &buf, "", 5, testBytes[0:len(testBytes)/i])
- empty(t, "TestLargeReads (2)", &buf, s, make([]byte, len(data)))
- }
- check(t, "TestLargeByteReads (3)", &buf, "")
-}
-
-func TestMixedReadsAndWrites(t *testing.T) {
- var buf Buffer
- s := ""
- for i := 0; i < 50; i++ {
- wlen := rand.Intn(len(data))
- s = fillBytes(t, "TestMixedReadsAndWrites (1)", &buf, s, 1, testBytes[0:wlen])
- rlen := rand.Intn(len(data))
- fub := make([]byte, rlen)
- n, _ := buf.Read(fub)
- s = s[n:]
- }
- empty(t, "TestMixedReadsAndWrites (2)", &buf, s, make([]byte, buf.Len()))
-}
-
-func TestNil(t *testing.T) {
- var b *Buffer
- if b.String() != "<nil>" {
- t.Errorf("expected <nil>; got %q", b.String())
- }
-}
-
-func TestReadFrom(t *testing.T) {
- var buf Buffer
- for i := 3; i < 30; i += 3 {
- s := fillBytes(t, "TestReadFrom (1)", &buf, "", 5, testBytes[0:len(testBytes)/i])
- var b Buffer
- b.ReadFrom(&buf)
- empty(t, "TestReadFrom (2)", &b, s, make([]byte, len(data)))
- }
-}
-
-func TestWriteTo(t *testing.T) {
- var buf Buffer
- for i := 3; i < 30; i += 3 {
- s := fillBytes(t, "TestWriteTo (1)", &buf, "", 5, testBytes[0:len(testBytes)/i])
- var b Buffer
- buf.WriteTo(&b)
- empty(t, "TestWriteTo (2)", &b, s, make([]byte, len(data)))
- }
-}
-
-func TestNext(t *testing.T) {
- b := []byte{0, 1, 2, 3, 4}
- tmp := make([]byte, 5)
- for i := 0; i <= 5; i++ {
- for j := i; j <= 5; j++ {
- for k := 0; k <= 6; k++ {
- // 0 <= i <= j <= 5; 0 <= k <= 6
- // Check that if we start with a buffer
- // of length j at offset i and ask for
- // Next(k), we get the right bytes.
- buf := NewBuffer(b[0:j])
- n, _ := buf.Read(tmp[0:i])
- if n != i {
- t.Fatalf("Read %d returned %d", i, n)
- }
- bb := buf.Next(k)
- want := k
- if want > j-i {
- want = j - i
- }
- if len(bb) != want {
- t.Fatalf("in %d,%d: len(Next(%d)) == %d", i, j, k, len(bb))
- }
- for l, v := range bb {
- if v != byte(l+i) {
- t.Fatalf("in %d,%d: Next(%d)[%d] = %d, want %d", i, j, k, l, v, l+i)
- }
- }
- }
- }
- }
-}
-
-var readBytesTests = []struct {
- buffer string
- delim byte
- expected []string
- err error
-}{
- {"", 0, []string{""}, io.EOF},
- {"a\x00", 0, []string{"a\x00"}, nil},
- {"abbbaaaba", 'b', []string{"ab", "b", "b", "aaab"}, nil},
- {"hello\x01world", 1, []string{"hello\x01"}, nil},
- {"foo\nbar", 0, []string{"foo\nbar"}, io.EOF},
- {"alpha\nbeta\ngamma\n", '\n', []string{"alpha\n", "beta\n", "gamma\n"}, nil},
- {"alpha\nbeta\ngamma", '\n', []string{"alpha\n", "beta\n", "gamma"}, io.EOF},
-}
-
-func TestReadBytes(t *testing.T) {
- for _, test := range readBytesTests {
- buf := NewBuffer([]byte(test.buffer))
- var err error
- for _, expected := range test.expected {
- var bytes []byte
- bytes, err = buf.ReadBytes(test.delim)
- if string(bytes) != expected {
- t.Errorf("expected %q, got %q", expected, bytes)
- }
- if err != nil {
- break
- }
- }
- if err != test.err {
- t.Errorf("expected error %v, got %v", test.err, err)
- }
- }
-}
-
-func TestGrow(t *testing.T) {
- x := []byte{'x'}
- y := []byte{'y'}
- tmp := make([]byte, 72)
- for _, startLen := range []int{0, 100, 1000, 10000, 100000} {
- xBytes := bytes.Repeat(x, startLen)
- for _, growLen := range []int{0, 100, 1000, 10000, 100000} {
- buf := NewBuffer(xBytes)
- // If we read, this affects buf.off, which is good to test.
- readBytes, _ := buf.Read(tmp)
- buf.Grow(growLen)
- yBytes := bytes.Repeat(y, growLen)
- // Check no allocation occurs in write, as long as we're single-threaded.
- var m1, m2 runtime.MemStats
- runtime.ReadMemStats(&m1)
- buf.Write(yBytes)
- runtime.ReadMemStats(&m2)
- if runtime.GOMAXPROCS(-1) == 1 && m1.Mallocs != m2.Mallocs {
- t.Errorf("allocation occurred during write")
- }
- // Check that buffer has correct data.
- if !bytes.Equal(buf.Bytes()[0:startLen-readBytes], xBytes[readBytes:]) {
- t.Errorf("bad initial data at %d %d", startLen, growLen)
- }
- if !bytes.Equal(buf.Bytes()[startLen-readBytes:startLen-readBytes+growLen], yBytes) {
- t.Errorf("bad written data at %d %d", startLen, growLen)
- }
- }
- }
-}
-
-// Was a bug: used to give EOF reading empty slice at EOF.
-func TestReadEmptyAtEOF(t *testing.T) {
- b := new(Buffer)
- slice := make([]byte, 0)
- n, err := b.Read(slice)
- if err != nil {
- t.Errorf("read error: %v", err)
- }
- if n != 0 {
- t.Errorf("wrong count; got %d want 0", n)
- }
-}
-
-// Tests that we occasionally compact. Issue 5154.
-func TestBufferGrowth(t *testing.T) {
- var b Buffer
- buf := make([]byte, 1024)
- b.Write(buf[0:1])
- var cap0 int
- for i := 0; i < 5<<10; i++ {
- b.Write(buf)
- b.Read(buf)
- if i == 0 {
- cap0 = cap(b.buf)
- }
- }
- cap1 := cap(b.buf)
- // (*Buffer).grow allows for 2x capacity slop before sliding,
- // so set our error threshold at 3x.
- if cap1 > cap0*3 {
- t.Errorf("buffer cap = %d; too big (grew from %d)", cap1, cap0)
- }
-}
-
-// From Issue 5154.
-func BenchmarkBufferNotEmptyWriteRead(b *testing.B) {
- buf := make([]byte, 1024)
- for i := 0; i < b.N; i++ {
- var b Buffer
- b.Write(buf[0:1])
- for i := 0; i < 5<<10; i++ {
- b.Write(buf)
- b.Read(buf)
- }
- }
-}
-
-// Check that we don't compact too often. From Issue 5154.
-func BenchmarkBufferFullSmallReads(b *testing.B) {
- buf := make([]byte, 1024)
- for i := 0; i < b.N; i++ {
- var b Buffer
- b.Write(buf)
- for b.Len()+20 < cap(b.buf) {
- b.Write(buf[:10])
- }
- for i := 0; i < 5<<10; i++ {
- b.Read(buf[:1])
- b.Write(buf[:1])
- }
- }
-}
diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/version.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/version.go
index 88a52f53e..50870ed83 100644
--- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/version.go
+++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/version.go
@@ -7,6 +7,7 @@
package leveldb
import (
+ "fmt"
"sync/atomic"
"unsafe"
@@ -23,7 +24,7 @@ type tSet struct {
type version struct {
s *session
- tables []tFiles
+ levels []tFiles
// Level that should be compacted next and its compaction score.
// Score < 1 means compaction is not strictly needed. These fields
@@ -39,7 +40,7 @@ type version struct {
}
func newVersion(s *session) *version {
- return &version{s: s, tables: make([]tFiles, s.o.GetNumLevel())}
+ return &version{s: s}
}
func (v *version) releaseNB() {
@@ -51,18 +52,18 @@ func (v *version) releaseNB() {
panic("negative version ref")
}
- tables := make(map[uint64]bool)
- for _, tt := range v.next.tables {
+ nextTables := make(map[int64]bool)
+ for _, tt := range v.next.levels {
for _, t := range tt {
- num := t.file.Num()
- tables[num] = true
+ num := t.fd.Num
+ nextTables[num] = true
}
}
- for _, tt := range v.tables {
+ for _, tt := range v.levels {
for _, t := range tt {
- num := t.file.Num()
- if _, ok := tables[num]; !ok {
+ num := t.fd.Num
+ if _, ok := nextTables[num]; !ok {
v.s.tops.remove(t)
}
}
@@ -78,11 +79,26 @@ func (v *version) release() {
v.s.vmu.Unlock()
}
-func (v *version) walkOverlapping(ikey iKey, f func(level int, t *tFile) bool, lf func(level int) bool) {
+func (v *version) walkOverlapping(aux tFiles, ikey iKey, f func(level int, t *tFile) bool, lf func(level int) bool) {
ukey := ikey.ukey()
+ // Aux level.
+ if aux != nil {
+ for _, t := range aux {
+ if t.overlaps(v.s.icmp, ukey, ukey) {
+ if !f(-1, t) {
+ return
+ }
+ }
+ }
+
+ if lf != nil && !lf(-1) {
+ return
+ }
+ }
+
// Walk tables level-by-level.
- for level, tables := range v.tables {
+ for level, tables := range v.levels {
if len(tables) == 0 {
continue
}
@@ -114,7 +130,7 @@ func (v *version) walkOverlapping(ikey iKey, f func(level int, t *tFile) bool, l
}
}
-func (v *version) get(ikey iKey, ro *opt.ReadOptions, noValue bool) (value []byte, tcomp bool, err error) {
+func (v *version) get(aux tFiles, ikey iKey, ro *opt.ReadOptions, noValue bool) (value []byte, tcomp bool, err error) {
ukey := ikey.ukey()
var (
@@ -130,10 +146,10 @@ func (v *version) get(ikey iKey, ro *opt.ReadOptions, noValue bool) (value []byt
err = ErrNotFound
- // Since entries never hope across level, finding key/value
+ // Since entries never hop across level, finding key/value
// in smaller level make later levels irrelevant.
- v.walkOverlapping(ikey, func(level int, t *tFile) bool {
- if !tseek {
+ v.walkOverlapping(aux, ikey, func(level int, t *tFile) bool {
+ if level >= 0 && !tseek {
if tset == nil {
tset = &tSet{level, t}
} else {
@@ -150,6 +166,7 @@ func (v *version) get(ikey iKey, ro *opt.ReadOptions, noValue bool) (value []byt
} else {
fikey, fval, ferr = v.s.tops.find(t, ikey, ro)
}
+
switch ferr {
case nil:
case ErrNotFound:
@@ -161,7 +178,8 @@ func (v *version) get(ikey iKey, ro *opt.ReadOptions, noValue bool) (value []byt
if fukey, fseq, fkt, fkerr := parseIkey(fikey); fkerr == nil {
if v.s.icmp.uCompare(ukey, fukey) == 0 {
- if level == 0 {
+ // Level <= 0 may overlaps each-other.
+ if level <= 0 {
if fseq >= zseq {
zfound = true
zseq = fseq
@@ -212,7 +230,7 @@ func (v *version) get(ikey iKey, ro *opt.ReadOptions, noValue bool) (value []byt
func (v *version) sampleSeek(ikey iKey) (tcomp bool) {
var tset *tSet
- v.walkOverlapping(ikey, func(level int, t *tFile) bool {
+ v.walkOverlapping(nil, ikey, func(level int, t *tFile) bool {
if tset == nil {
tset = &tSet{level, t}
return true
@@ -228,27 +246,22 @@ func (v *version) sampleSeek(ikey iKey) (tcomp bool) {
}
func (v *version) getIterators(slice *util.Range, ro *opt.ReadOptions) (its []iterator.Iterator) {
- // Merge all level zero files together since they may overlap
- for _, t := range v.tables[0] {
- it := v.s.tops.newIterator(t, slice, ro)
- its = append(its, it)
- }
-
strict := opt.GetStrict(v.s.o.Options, ro, opt.StrictReader)
- for _, tables := range v.tables[1:] {
- if len(tables) == 0 {
- continue
+ for level, tables := range v.levels {
+ if level == 0 {
+ // Merge all level zero files together since they may overlap.
+ for _, t := range tables {
+ its = append(its, v.s.tops.newIterator(t, slice, ro))
+ }
+ } else if len(tables) != 0 {
+ its = append(its, iterator.NewIndexedIterator(tables.newIndexIterator(v.s.tops, v.s.icmp, slice, ro), strict))
}
-
- it := iterator.NewIndexedIterator(tables.newIndexIterator(v.s.tops, v.s.icmp, slice, ro), strict)
- its = append(its, it)
}
-
return
}
func (v *version) newStaging() *versionStaging {
- return &versionStaging{base: v, tables: make([]tablesScratch, v.s.o.GetNumLevel())}
+ return &versionStaging{base: v}
}
// Spawn a new version based on this version.
@@ -259,23 +272,26 @@ func (v *version) spawn(r *sessionRecord) *version {
}
func (v *version) fillRecord(r *sessionRecord) {
- for level, ts := range v.tables {
- for _, t := range ts {
+ for level, tables := range v.levels {
+ for _, t := range tables {
r.addTableFile(level, t)
}
}
}
func (v *version) tLen(level int) int {
- return len(v.tables[level])
+ if level < len(v.levels) {
+ return len(v.levels[level])
+ }
+ return 0
}
func (v *version) offsetOf(ikey iKey) (n uint64, err error) {
- for level, tables := range v.tables {
+ for level, tables := range v.levels {
for _, t := range tables {
if v.s.icmp.Compare(t.imax, ikey) <= 0 {
// Entire file is before "ikey", so just add the file size
- n += t.size
+ n += uint64(t.size)
} else if v.s.icmp.Compare(t.imin, ikey) > 0 {
// Entire file is after "ikey", so ignore
if level > 0 {
@@ -300,37 +316,50 @@ func (v *version) offsetOf(ikey iKey) (n uint64, err error) {
return
}
-func (v *version) pickLevel(umin, umax []byte) (level int) {
- if !v.tables[0].overlaps(v.s.icmp, umin, umax, true) {
- var overlaps tFiles
- maxLevel := v.s.o.GetMaxMemCompationLevel()
- for ; level < maxLevel; level++ {
- if v.tables[level+1].overlaps(v.s.icmp, umin, umax, false) {
- break
- }
- overlaps = v.tables[level+2].getOverlaps(overlaps, v.s.icmp, umin, umax, false)
- if overlaps.size() > uint64(v.s.o.GetCompactionGPOverlaps(level)) {
- break
+func (v *version) pickMemdbLevel(umin, umax []byte, maxLevel int) (level int) {
+ if maxLevel > 0 {
+ if len(v.levels) == 0 {
+ return maxLevel
+ }
+ if !v.levels[0].overlaps(v.s.icmp, umin, umax, true) {
+ var overlaps tFiles
+ for ; level < maxLevel; level++ {
+ if pLevel := level + 1; pLevel >= len(v.levels) {
+ return maxLevel
+ } else if v.levels[pLevel].overlaps(v.s.icmp, umin, umax, false) {
+ break
+ }
+ if gpLevel := level + 2; gpLevel < len(v.levels) {
+ overlaps = v.levels[gpLevel].getOverlaps(overlaps, v.s.icmp, umin, umax, false)
+ if overlaps.size() > int64(v.s.o.GetCompactionGPOverlaps(level)) {
+ break
+ }
+ }
}
}
}
-
return
}
func (v *version) computeCompaction() {
// Precomputed best level for next compaction
- var bestLevel int = -1
- var bestScore float64 = -1
+ bestLevel := int(-1)
+ bestScore := float64(-1)
- for level, tables := range v.tables {
+ statFiles := make([]int, len(v.levels))
+ statSizes := make([]string, len(v.levels))
+ statScore := make([]string, len(v.levels))
+ statTotSize := int64(0)
+
+ for level, tables := range v.levels {
var score float64
+ size := tables.size()
if level == 0 {
// We treat level-0 specially by bounding the number of files
// instead of number of bytes for two reasons:
//
// (1) With larger write-buffer sizes, it is nice not to do too
- // many level-0 compactions.
+ // many level-0 compaction.
//
// (2) The files in level-0 are merged on every read and
// therefore we wish to avoid too many files when the individual
@@ -339,17 +368,24 @@ func (v *version) computeCompaction() {
// overwrites/deletions).
score = float64(len(tables)) / float64(v.s.o.GetCompactionL0Trigger())
} else {
- score = float64(tables.size()) / float64(v.s.o.GetCompactionTotalSize(level))
+ score = float64(size) / float64(v.s.o.GetCompactionTotalSize(level))
}
if score > bestScore {
bestLevel = level
bestScore = score
}
+
+ statFiles[level] = len(tables)
+ statSizes[level] = shortenb(int(size))
+ statScore[level] = fmt.Sprintf("%.2f", score)
+ statTotSize += size
}
v.cLevel = bestLevel
v.cScore = bestScore
+
+ v.s.logf("version@stat F·%v S·%s%v Sc·%v", statFiles, shortenb(int(statTotSize)), statSizes, statScore)
}
func (v *version) needCompaction() bool {
@@ -357,43 +393,48 @@ func (v *version) needCompaction() bool {
}
type tablesScratch struct {
- added map[uint64]atRecord
- deleted map[uint64]struct{}
+ added map[int64]atRecord
+ deleted map[int64]struct{}
}
type versionStaging struct {
base *version
- tables []tablesScratch
+ levels []tablesScratch
+}
+
+func (p *versionStaging) getScratch(level int) *tablesScratch {
+ if level >= len(p.levels) {
+ newLevels := make([]tablesScratch, level+1)
+ copy(newLevels, p.levels)
+ p.levels = newLevels
+ }
+ return &(p.levels[level])
}
func (p *versionStaging) commit(r *sessionRecord) {
// Deleted tables.
for _, r := range r.deletedTables {
- tm := &(p.tables[r.level])
-
- if len(p.base.tables[r.level]) > 0 {
- if tm.deleted == nil {
- tm.deleted = make(map[uint64]struct{})
+ scratch := p.getScratch(r.level)
+ if r.level < len(p.base.levels) && len(p.base.levels[r.level]) > 0 {
+ if scratch.deleted == nil {
+ scratch.deleted = make(map[int64]struct{})
}
- tm.deleted[r.num] = struct{}{}
+ scratch.deleted[r.num] = struct{}{}
}
-
- if tm.added != nil {
- delete(tm.added, r.num)
+ if scratch.added != nil {
+ delete(scratch.added, r.num)
}
}
// New tables.
for _, r := range r.addedTables {
- tm := &(p.tables[r.level])
-
- if tm.added == nil {
- tm.added = make(map[uint64]atRecord)
+ scratch := p.getScratch(r.level)
+ if scratch.added == nil {
+ scratch.added = make(map[int64]atRecord)
}
- tm.added[r.num] = r
-
- if tm.deleted != nil {
- delete(tm.deleted, r.num)
+ scratch.added[r.num] = r
+ if scratch.deleted != nil {
+ delete(scratch.deleted, r.num)
}
}
}
@@ -401,40 +442,63 @@ func (p *versionStaging) commit(r *sessionRecord) {
func (p *versionStaging) finish() *version {
// Build new version.
nv := newVersion(p.base.s)
- for level, tm := range p.tables {
- btables := p.base.tables[level]
-
- n := len(btables) + len(tm.added) - len(tm.deleted)
- if n < 0 {
- n = 0
+ numLevel := len(p.levels)
+ if len(p.base.levels) > numLevel {
+ numLevel = len(p.base.levels)
+ }
+ nv.levels = make([]tFiles, numLevel)
+ for level := 0; level < numLevel; level++ {
+ var baseTabels tFiles
+ if level < len(p.base.levels) {
+ baseTabels = p.base.levels[level]
}
- nt := make(tFiles, 0, n)
- // Base tables.
- for _, t := range btables {
- if _, ok := tm.deleted[t.file.Num()]; ok {
- continue
+ if level < len(p.levels) {
+ scratch := p.levels[level]
+
+ var nt tFiles
+ // Prealloc list if possible.
+ if n := len(baseTabels) + len(scratch.added) - len(scratch.deleted); n > 0 {
+ nt = make(tFiles, 0, n)
}
- if _, ok := tm.added[t.file.Num()]; ok {
- continue
+
+ // Base tables.
+ for _, t := range baseTabels {
+ if _, ok := scratch.deleted[t.fd.Num]; ok {
+ continue
+ }
+ if _, ok := scratch.added[t.fd.Num]; ok {
+ continue
+ }
+ nt = append(nt, t)
}
- nt = append(nt, t)
- }
- // New tables.
- for _, r := range tm.added {
- nt = append(nt, p.base.s.tableFileFromRecord(r))
- }
+ // New tables.
+ for _, r := range scratch.added {
+ nt = append(nt, tableFileFromRecord(r))
+ }
- // Sort tables.
- if level == 0 {
- nt.sortByNum()
+ if len(nt) != 0 {
+ // Sort tables.
+ if level == 0 {
+ nt.sortByNum()
+ } else {
+ nt.sortByKey(p.base.s.icmp)
+ }
+
+ nv.levels[level] = nt
+ }
} else {
- nt.sortByKey(p.base.s.icmp)
+ nv.levels[level] = baseTabels
}
- nv.tables[level] = nt
}
+ // Trim levels.
+ n := len(nv.levels)
+ for ; n > 0 && nv.levels[n-1] == nil; n-- {
+ }
+ nv.levels = nv.levels[:n]
+
// Compute compaction score for new version.
nv.computeCompaction()
diff --git a/Godeps/_workspace/src/github.com/syndtr/gosnappy/LICENSE b/Godeps/_workspace/src/github.com/syndtr/gosnappy/LICENSE
new file mode 100644
index 000000000..6050c10f4
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/syndtr/gosnappy/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2011 The Snappy-Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * 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.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+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
+OWNER 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.
diff --git a/Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/snappy_test.go b/Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/snappy_test.go
deleted file mode 100644
index 0623385b7..000000000
--- a/Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/snappy_test.go
+++ /dev/null
@@ -1,364 +0,0 @@
-// Copyright 2011 The Snappy-Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package snappy
-
-import (
- "bytes"
- "flag"
- "fmt"
- "io"
- "io/ioutil"
- "math/rand"
- "net/http"
- "os"
- "path/filepath"
- "strings"
- "testing"
-)
-
-var (
- download = flag.Bool("download", false, "If true, download any missing files before running benchmarks")
- testdata = flag.String("testdata", "testdata", "Directory containing the test data")
-)
-
-func roundtrip(b, ebuf, dbuf []byte) error {
- e, err := Encode(ebuf, b)
- if err != nil {
- return fmt.Errorf("encoding error: %v", err)
- }
- d, err := Decode(dbuf, e)
- if err != nil {
- return fmt.Errorf("decoding error: %v", err)
- }
- if !bytes.Equal(b, d) {
- return fmt.Errorf("roundtrip mismatch:\n\twant %v\n\tgot %v", b, d)
- }
- return nil
-}
-
-func TestEmpty(t *testing.T) {
- if err := roundtrip(nil, nil, nil); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestSmallCopy(t *testing.T) {
- for _, ebuf := range [][]byte{nil, make([]byte, 20), make([]byte, 64)} {
- for _, dbuf := range [][]byte{nil, make([]byte, 20), make([]byte, 64)} {
- for i := 0; i < 32; i++ {
- s := "aaaa" + strings.Repeat("b", i) + "aaaabbbb"
- if err := roundtrip([]byte(s), ebuf, dbuf); err != nil {
- t.Errorf("len(ebuf)=%d, len(dbuf)=%d, i=%d: %v", len(ebuf), len(dbuf), i, err)
- }
- }
- }
- }
-}
-
-func TestSmallRand(t *testing.T) {
- rng := rand.New(rand.NewSource(27354294))
- for n := 1; n < 20000; n += 23 {
- b := make([]byte, n)
- for i := range b {
- b[i] = uint8(rng.Uint32())
- }
- if err := roundtrip(b, nil, nil); err != nil {
- t.Fatal(err)
- }
- }
-}
-
-func TestSmallRegular(t *testing.T) {
- for n := 1; n < 20000; n += 23 {
- b := make([]byte, n)
- for i := range b {
- b[i] = uint8(i%10 + 'a')
- }
- if err := roundtrip(b, nil, nil); err != nil {
- t.Fatal(err)
- }
- }
-}
-
-func cmp(a, b []byte) error {
- if len(a) != len(b) {
- return fmt.Errorf("got %d bytes, want %d", len(a), len(b))
- }
- for i := range a {
- if a[i] != b[i] {
- return fmt.Errorf("byte #%d: got 0x%02x, want 0x%02x", i, a[i], b[i])
- }
- }
- return nil
-}
-
-func TestFramingFormat(t *testing.T) {
- // src is comprised of alternating 1e5-sized sequences of random
- // (incompressible) bytes and repeated (compressible) bytes. 1e5 was chosen
- // because it is larger than maxUncompressedChunkLen (64k).
- src := make([]byte, 1e6)
- rng := rand.New(rand.NewSource(1))
- for i := 0; i < 10; i++ {
- if i%2 == 0 {
- for j := 0; j < 1e5; j++ {
- src[1e5*i+j] = uint8(rng.Intn(256))
- }
- } else {
- for j := 0; j < 1e5; j++ {
- src[1e5*i+j] = uint8(i)
- }
- }
- }
-
- buf := new(bytes.Buffer)
- if _, err := NewWriter(buf).Write(src); err != nil {
- t.Fatalf("Write: encoding: %v", err)
- }
- dst, err := ioutil.ReadAll(NewReader(buf))
- if err != nil {
- t.Fatalf("ReadAll: decoding: %v", err)
- }
- if err := cmp(dst, src); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestReaderReset(t *testing.T) {
- gold := bytes.Repeat([]byte("All that is gold does not glitter,\n"), 10000)
- buf := new(bytes.Buffer)
- if _, err := NewWriter(buf).Write(gold); err != nil {
- t.Fatalf("Write: %v", err)
- }
- encoded, invalid, partial := buf.String(), "invalid", "partial"
- r := NewReader(nil)
- for i, s := range []string{encoded, invalid, partial, encoded, partial, invalid, encoded, encoded} {
- if s == partial {
- r.Reset(strings.NewReader(encoded))
- if _, err := r.Read(make([]byte, 101)); err != nil {
- t.Errorf("#%d: %v", i, err)
- continue
- }
- continue
- }
- r.Reset(strings.NewReader(s))
- got, err := ioutil.ReadAll(r)
- switch s {
- case encoded:
- if err != nil {
- t.Errorf("#%d: %v", i, err)
- continue
- }
- if err := cmp(got, gold); err != nil {
- t.Errorf("#%d: %v", i, err)
- continue
- }
- case invalid:
- if err == nil {
- t.Errorf("#%d: got nil error, want non-nil", i)
- continue
- }
- }
- }
-}
-
-func TestWriterReset(t *testing.T) {
- gold := bytes.Repeat([]byte("Not all those who wander are lost;\n"), 10000)
- var gots, wants [][]byte
- const n = 20
- w, failed := NewWriter(nil), false
- for i := 0; i <= n; i++ {
- buf := new(bytes.Buffer)
- w.Reset(buf)
- want := gold[:len(gold)*i/n]
- if _, err := w.Write(want); err != nil {
- t.Errorf("#%d: Write: %v", i, err)
- failed = true
- continue
- }
- got, err := ioutil.ReadAll(NewReader(buf))
- if err != nil {
- t.Errorf("#%d: ReadAll: %v", i, err)
- failed = true
- continue
- }
- gots = append(gots, got)
- wants = append(wants, want)
- }
- if failed {
- return
- }
- for i := range gots {
- if err := cmp(gots[i], wants[i]); err != nil {
- t.Errorf("#%d: %v", i, err)
- }
- }
-}
-
-func benchDecode(b *testing.B, src []byte) {
- encoded, err := Encode(nil, src)
- if err != nil {
- b.Fatal(err)
- }
- // Bandwidth is in amount of uncompressed data.
- b.SetBytes(int64(len(src)))
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- Decode(src, encoded)
- }
-}
-
-func benchEncode(b *testing.B, src []byte) {
- // Bandwidth is in amount of uncompressed data.
- b.SetBytes(int64(len(src)))
- dst := make([]byte, MaxEncodedLen(len(src)))
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- Encode(dst, src)
- }
-}
-
-func readFile(b testing.TB, filename string) []byte {
- src, err := ioutil.ReadFile(filename)
- if err != nil {
- b.Fatalf("failed reading %s: %s", filename, err)
- }
- if len(src) == 0 {
- b.Fatalf("%s has zero length", filename)
- }
- return src
-}
-
-// expand returns a slice of length n containing repeated copies of src.
-func expand(src []byte, n int) []byte {
- dst := make([]byte, n)
- for x := dst; len(x) > 0; {
- i := copy(x, src)
- x = x[i:]
- }
- return dst
-}
-
-func benchWords(b *testing.B, n int, decode bool) {
- // Note: the file is OS-language dependent so the resulting values are not
- // directly comparable for non-US-English OS installations.
- data := expand(readFile(b, "/usr/share/dict/words"), n)
- if decode {
- benchDecode(b, data)
- } else {
- benchEncode(b, data)
- }
-}
-
-func BenchmarkWordsDecode1e3(b *testing.B) { benchWords(b, 1e3, true) }
-func BenchmarkWordsDecode1e4(b *testing.B) { benchWords(b, 1e4, true) }
-func BenchmarkWordsDecode1e5(b *testing.B) { benchWords(b, 1e5, true) }
-func BenchmarkWordsDecode1e6(b *testing.B) { benchWords(b, 1e6, true) }
-func BenchmarkWordsEncode1e3(b *testing.B) { benchWords(b, 1e3, false) }
-func BenchmarkWordsEncode1e4(b *testing.B) { benchWords(b, 1e4, false) }
-func BenchmarkWordsEncode1e5(b *testing.B) { benchWords(b, 1e5, false) }
-func BenchmarkWordsEncode1e6(b *testing.B) { benchWords(b, 1e6, false) }
-
-// testFiles' values are copied directly from
-// https://raw.githubusercontent.com/google/snappy/master/snappy_unittest.cc
-// The label field is unused in snappy-go.
-var testFiles = []struct {
- label string
- filename string
-}{
- {"html", "html"},
- {"urls", "urls.10K"},
- {"jpg", "fireworks.jpeg"},
- {"jpg_200", "fireworks.jpeg"},
- {"pdf", "paper-100k.pdf"},
- {"html4", "html_x_4"},
- {"txt1", "alice29.txt"},
- {"txt2", "asyoulik.txt"},
- {"txt3", "lcet10.txt"},
- {"txt4", "plrabn12.txt"},
- {"pb", "geo.protodata"},
- {"gaviota", "kppkn.gtb"},
-}
-
-// The test data files are present at this canonical URL.
-const baseURL = "https://raw.githubusercontent.com/google/snappy/master/testdata/"
-
-func downloadTestdata(basename string) (errRet error) {
- filename := filepath.Join(*testdata, basename)
- if stat, err := os.Stat(filename); err == nil && stat.Size() != 0 {
- return nil
- }
-
- if !*download {
- return fmt.Errorf("test data not found; skipping benchmark without the -download flag")
- }
- // Download the official snappy C++ implementation reference test data
- // files for benchmarking.
- if err := os.Mkdir(*testdata, 0777); err != nil && !os.IsExist(err) {
- return fmt.Errorf("failed to create testdata: %s", err)
- }
-
- f, err := os.Create(filename)
- if err != nil {
- return fmt.Errorf("failed to create %s: %s", filename, err)
- }
- defer f.Close()
- defer func() {
- if errRet != nil {
- os.Remove(filename)
- }
- }()
- url := baseURL + basename
- resp, err := http.Get(url)
- if err != nil {
- return fmt.Errorf("failed to download %s: %s", url, err)
- }
- defer resp.Body.Close()
- if s := resp.StatusCode; s != http.StatusOK {
- return fmt.Errorf("downloading %s: HTTP status code %d (%s)", url, s, http.StatusText(s))
- }
- _, err = io.Copy(f, resp.Body)
- if err != nil {
- return fmt.Errorf("failed to download %s to %s: %s", url, filename, err)
- }
- return nil
-}
-
-func benchFile(b *testing.B, n int, decode bool) {
- if err := downloadTestdata(testFiles[n].filename); err != nil {
- b.Fatalf("failed to download testdata: %s", err)
- }
- data := readFile(b, filepath.Join(*testdata, testFiles[n].filename))
- if decode {
- benchDecode(b, data)
- } else {
- benchEncode(b, data)
- }
-}
-
-// Naming convention is kept similar to what snappy's C++ implementation uses.
-func Benchmark_UFlat0(b *testing.B) { benchFile(b, 0, true) }
-func Benchmark_UFlat1(b *testing.B) { benchFile(b, 1, true) }
-func Benchmark_UFlat2(b *testing.B) { benchFile(b, 2, true) }
-func Benchmark_UFlat3(b *testing.B) { benchFile(b, 3, true) }
-func Benchmark_UFlat4(b *testing.B) { benchFile(b, 4, true) }
-func Benchmark_UFlat5(b *testing.B) { benchFile(b, 5, true) }
-func Benchmark_UFlat6(b *testing.B) { benchFile(b, 6, true) }
-func Benchmark_UFlat7(b *testing.B) { benchFile(b, 7, true) }
-func Benchmark_UFlat8(b *testing.B) { benchFile(b, 8, true) }
-func Benchmark_UFlat9(b *testing.B) { benchFile(b, 9, true) }
-func Benchmark_UFlat10(b *testing.B) { benchFile(b, 10, true) }
-func Benchmark_UFlat11(b *testing.B) { benchFile(b, 11, true) }
-func Benchmark_ZFlat0(b *testing.B) { benchFile(b, 0, false) }
-func Benchmark_ZFlat1(b *testing.B) { benchFile(b, 1, false) }
-func Benchmark_ZFlat2(b *testing.B) { benchFile(b, 2, false) }
-func Benchmark_ZFlat3(b *testing.B) { benchFile(b, 3, false) }
-func Benchmark_ZFlat4(b *testing.B) { benchFile(b, 4, false) }
-func Benchmark_ZFlat5(b *testing.B) { benchFile(b, 5, false) }
-func Benchmark_ZFlat6(b *testing.B) { benchFile(b, 6, false) }
-func Benchmark_ZFlat7(b *testing.B) { benchFile(b, 7, false) }
-func Benchmark_ZFlat8(b *testing.B) { benchFile(b, 8, false) }
-func Benchmark_ZFlat9(b *testing.B) { benchFile(b, 9, false) }
-func Benchmark_ZFlat10(b *testing.B) { benchFile(b, 10, false) }
-func Benchmark_ZFlat11(b *testing.B) { benchFile(b, 11, false) }