speckle 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +22 -0
  3. data/Gemfile +2 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +39 -0
  6. data/Rakefile +230 -0
  7. data/bin/speckle +12 -0
  8. data/lib/dsl.riml +29 -0
  9. data/lib/expectation.riml +34 -0
  10. data/lib/matchers/above_matcher.riml +13 -0
  11. data/lib/matchers/atleast_matcher.riml +13 -0
  12. data/lib/matchers/atmost_matcher.riml +13 -0
  13. data/lib/matchers/below_matcher.riml +13 -0
  14. data/lib/matchers/between_matcher.riml +19 -0
  15. data/lib/matchers/boolean_matcher.riml +13 -0
  16. data/lib/matchers/dict_key_matcher.riml +14 -0
  17. data/lib/matchers/equality_matcher.riml +13 -0
  18. data/lib/matchers/existance_matcher.riml +13 -0
  19. data/lib/matchers/length_matcher.riml +14 -0
  20. data/lib/matchers/match_item.riml +8 -0
  21. data/lib/matchers/match_tester.riml +33 -0
  22. data/lib/matchers/matchers.riml +72 -0
  23. data/lib/matchers/regexp_matcher.riml +14 -0
  24. data/lib/matchers/within_matcher.riml +28 -0
  25. data/lib/reporters/base_reporter.riml +126 -0
  26. data/lib/reporters/dotmatrix_reporter.riml +47 -0
  27. data/lib/reporters/min_reporter.riml +13 -0
  28. data/lib/reporters/reporter_factory.riml +15 -0
  29. data/lib/reporters/spec_reporter.riml +58 -0
  30. data/lib/reporters/tap_reporter.riml +38 -0
  31. data/lib/runners/runner.riml +49 -0
  32. data/lib/runners/spec_runner.riml +96 -0
  33. data/lib/speckle/cli/app.rb +18 -0
  34. data/lib/speckle/cli/controller.rb +67 -0
  35. data/lib/speckle/cli/environment.rb +148 -0
  36. data/lib/speckle/cli/rake_app.rb +146 -0
  37. data/lib/speckle/cli/router.rb +16 -0
  38. data/lib/speckle/loader.rb +10 -0
  39. data/lib/speckle/version.rb +3 -0
  40. data/lib/speckle.rb +4 -0
  41. data/lib/speckle.riml +148 -0
  42. data/lib/utils/spec_meta.riml +30 -0
  43. data/lib/utils/spec_timer.riml +30 -0
  44. data/lib/utils/statistician.riml +70 -0
  45. data/lib/writers/buffer_writer.riml +37 -0
  46. data/lib/writers/console_writer.riml +28 -0
  47. data/lib/writers/file_writer.riml +31 -0
  48. data/lib/writers/writer_factory.riml +13 -0
  49. data/spec/after_hooks_spec.riml +58 -0
  50. data/spec/before_hooks_spec.riml +38 -0
  51. data/spec/matchers/above_matcher_spec.riml +27 -0
  52. data/spec/matchers/atleast_matcher_spec.riml +28 -0
  53. data/spec/matchers/atmost_matcher_spec.riml +29 -0
  54. data/spec/matchers/below_matcher_spec.riml +28 -0
  55. data/spec/matchers/between_matcher_spec.riml +17 -0
  56. data/spec/matchers/boolean_matcher_spec.riml +27 -0
  57. data/spec/matchers/custom_matcher_spec.riml +47 -0
  58. data/spec/matchers/dict_key_matcher_spec.riml +19 -0
  59. data/spec/matchers/equality_matcher_spec.riml +31 -0
  60. data/spec/matchers/existance_matcher_spec.riml +17 -0
  61. data/spec/matchers/length_matcher_spec.riml +18 -0
  62. data/spec/matchers/regexp_matcher_spec.riml +31 -0
  63. data/spec/matchers/within_matcher_spec.riml +18 -0
  64. data/spec/spec_helper.rb +1 -0
  65. data/spec/speckle/cli/environment_spec.rb +296 -0
  66. data/speckle.gemspec +30 -0
  67. metadata +210 -0
@@ -0,0 +1,14 @@
1
+ class RegExpMatcher
2
+ defm match(pattern, expr)
3
+ result = matchstr(expr, pattern)
4
+ return empty(result) == false
5
+ end
6
+
7
+ defm failure_message_for_match(pattern, expr)
8
+ return "expected “#{pattern}” to match #{expr}"
9
+ end
10
+
11
+ defm failure_message_for_mismatch(pattern, expr)
12
+ return "expected “#{pattern}” to not match #{expr}"
13
+ end
14
+ end
@@ -0,0 +1,28 @@
1
+ class WithinMatcher
2
+ defm match(expected, actual)
3
+ delta = expected[0]
4
+ num = expected[1]
5
+ self.result = abs(num - actual)
6
+ return self.result <= delta
7
+ end
8
+
9
+ defm failure_message_for_match(expected, actual)
10
+ delta = expected[0]
11
+ num = expected[1]
12
+ actual_str = printf("%f", actual)
13
+ delta_str = printf("%f", delta)
14
+ num_str = printf("%f", num)
15
+ result_str = printf('%f', self.result)
16
+ return "expected “#{actual_str}” to be within +/- “#{delta_str}” of “#{num_str}”, delta was “#{result_str}”"
17
+ end
18
+
19
+ defm failure_message_for_mismatch(expected, actual)
20
+ delta = expected[0]
21
+ num = expected[1]
22
+ actual_str = printf("%f", actual)
23
+ delta_str = printf("%f", delta)
24
+ num_str = printf("%f", num)
25
+ result_str = printf('%f', self.result)
26
+ return "expected “#{actual_str}” to not be within +/- “#{delta_str}” of “#{num_str}”, delta was “#{result_str}”"
27
+ end
28
+ end
@@ -0,0 +1,126 @@
1
+ class BaseReporter
2
+ def initialize()
3
+ self.colorize_output = true
4
+ end
5
+
6
+ defm set_writer(writer)
7
+ self.writer = writer
8
+ end
9
+
10
+ defm on_start(stats)
11
+ end
12
+
13
+ defm on_end(duration, stats)
14
+ self.write_epilogue(duration, stats)
15
+ end
16
+
17
+ defm on_context_start(context, stats)
18
+ end
19
+
20
+ defm on_context_end(context, stats)
21
+ end
22
+
23
+ defm on_spec_start(meta, stats)
24
+ end
25
+
26
+ defm on_spec_end(meta, stats)
27
+ end
28
+
29
+ defm on_spec_pass(meta, stats)
30
+ end
31
+
32
+ defm on_spec_failure(meta, err, stats)
33
+ end
34
+
35
+ defm on_spec_error(meta, err, stats)
36
+ end
37
+
38
+ defm on_spec_pending(meta, stats)
39
+ end
40
+
41
+ defm duration_to_str(duration)
42
+ time = a:duration
43
+ if time >= 1000
44
+ time = time / 1000
45
+ return "#{time}s"
46
+ else
47
+ return "#{time}ms"
48
+ end
49
+ end
50
+
51
+ defm get_duration_msg(meta)
52
+ if meta.is_slow()
53
+ duration_str = self.duration_to_str(meta.get_duration())
54
+ return "(#{duration_str})"
55
+ else
56
+ return ''
57
+ end
58
+ end
59
+
60
+ defm write_epilogue_separator
61
+ self.writer.writeln("----------------------------------------------------")
62
+ end
63
+
64
+ defm write_epilogue(duration, stats)
65
+ self.write_epilogue_separator()
66
+ duration_str = self.duration_to_str(duration)
67
+ if stats.is_ok()
68
+ icon = self.get_tick_icon()
69
+ else
70
+ icon = self.get_cross_icon()
71
+ end
72
+
73
+ self.writer.writeln(self.to_color("#{icon} #{stats.get_count()} tests completed (#{duration_str})", stats))
74
+ self.writer.writeln("Passed: #{stats.get_passes()}, Failures: #{stats.get_failures()}, Errors: #{stats.get_errors()}, Assertions: #{stats.get_assertions()}")
75
+ end
76
+
77
+ defm set_colorize_output(colorize_output)
78
+ self.colorize_output = colorize_output
79
+ end
80
+
81
+ defm get_colorize_output()
82
+ return self.colorize_output
83
+ end
84
+
85
+ defm colorize(str, color)
86
+ if self.get_colorize_output()
87
+ return "[#{color}#{str}"
88
+ else
89
+ return str
90
+ end
91
+ end
92
+
93
+ defm to_color(str, stats)
94
+ if stats.is_ok()
95
+ return self.to_green(str)
96
+ else
97
+ return self.to_red(str)
98
+ end
99
+ end
100
+
101
+ defm to_red(str)
102
+ return self.colorize(str, '31m')
103
+ end
104
+
105
+ defm to_green(str)
106
+ return self.colorize(str, '32m')
107
+ end
108
+
109
+ defm get_tick_icon()
110
+ return '✓'
111
+ end
112
+
113
+ defm get_cross_icon()
114
+ return '✖'
115
+ end
116
+
117
+ defm get_tick()
118
+ return self.to_green(self.get_tick_icon())
119
+ end
120
+
121
+ defm get_cross()
122
+ return self.to_red(self.get_cross_icon())
123
+ end
124
+
125
+ end
126
+
@@ -0,0 +1,47 @@
1
+ class DotMatrixReporter < BaseReporter
2
+
3
+ def initialize()
4
+ super()
5
+ self.dots = 0
6
+ self.line_buffer = []
7
+ end
8
+
9
+ defm write(msg)
10
+ if self.dots > 50
11
+ self.writer.writeln(msg)
12
+ self.dots = 0
13
+ else
14
+ self.writer.write(msg)
15
+ end
16
+ end
17
+
18
+ defm on_spec_pass(meta, stats)
19
+ self.dots += 1
20
+ self.write('.')
21
+ end
22
+
23
+ defm on_spec_failure(meta, err, stats)
24
+ self.dots += 1
25
+ self.write(self.to_red("x"))
26
+
27
+ name = meta.get_sentence()
28
+ context = meta.get_context()
29
+ add(self.line_buffer, self.to_red("#{context} ##{name}"))
30
+ add(self.line_buffer, self.to_red(" #{err}"))
31
+ add(self.line_buffer, '')
32
+ end
33
+
34
+ defm on_spec_error(meta, err, stats)
35
+ self.on_spec_failure(meta, err, stats)
36
+ end
37
+
38
+ defm write_epilogue_separator()
39
+ self.writer.writeln('')
40
+ for line in self.line_buffer
41
+ self.writer.writeln(line)
42
+ end
43
+
44
+ self.writer.writeln("")
45
+ end
46
+
47
+ end
@@ -0,0 +1,13 @@
1
+ class MinReporter < BaseReporter
2
+
3
+ defm on_spec_failure(meta, err, stats)
4
+ name = meta.get_sentence()
5
+ context = meta.get_context()
6
+ self.writer.writeln(self.to_red("#{context} ##{name} - #{err}"))
7
+ end
8
+
9
+ defm on_spec_error(meta, err, stats)
10
+ self.on_spec_failure(meta, err, stats)
11
+ end
12
+
13
+ end
@@ -0,0 +1,15 @@
1
+ class ReporterFactory
2
+ defm get_reporter(reporter_name)
3
+ if a:reporter_name == 'spec'
4
+ return new SpecReporter()
5
+ elseif a:reporter_name == 'min'
6
+ return new MinReporter()
7
+ elseif a:reporter_name == 'tap'
8
+ return new TAPReporter()
9
+ elseif a:reporter_name == 'dot'
10
+ return new DotMatrixReporter()
11
+ else
12
+ return new SpecReporter()
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,58 @@
1
+ class SpecReporter < BaseReporter
2
+
3
+ def initialize()
4
+ super()
5
+ self.indents = 0
6
+ end
7
+
8
+ defm write(msg)
9
+ line = "#{self.indent_to_str()}#{msg}"
10
+ self.writer.writeln(line)
11
+ end
12
+
13
+ defm on_start(stats)
14
+ end
15
+
16
+ defm on_context_start(context, stats)
17
+ self.write("#{context}")
18
+ self.indent(1)
19
+ end
20
+
21
+ defm on_context_end(context, stats)
22
+ self.unindent(1)
23
+ end
24
+
25
+ defm on_spec_pass(meta, stats)
26
+ duration_msg = self.get_duration_msg(meta)
27
+ self.write("#{self.get_tick()} #{meta.get_sentence()} #{duration_msg}")
28
+ end
29
+
30
+ defm on_spec_failure(meta, err, stats)
31
+ self.write("#{self.get_cross()} #{self.to_red(meta.get_sentence())}")
32
+ self.indent(2)
33
+ self.write(self.to_red(err))
34
+ self.unindent(2)
35
+ end
36
+
37
+ defm on_spec_error(meta, err, stats)
38
+ self.on_spec_failure(meta, err, stats)
39
+ end
40
+
41
+ defm indent_to_str()
42
+ return repeat(" ", self.indents)
43
+ end
44
+
45
+ defm indent(size)
46
+ self.indents += size
47
+ end
48
+
49
+ defm unindent(size)
50
+ self.indents -= size
51
+ end
52
+
53
+ defm write_epilogue_separator()
54
+ self.writer.writeln('')
55
+ super()
56
+ end
57
+
58
+ end
@@ -0,0 +1,38 @@
1
+ class TAPReporter < BaseReporter
2
+ defm on_start(stats)
3
+ end
4
+
5
+ defm on_spec_start(meta, stats)
6
+ end
7
+
8
+ defm on_spec_end(meta, stats)
9
+ end
10
+
11
+ defm on_spec_pass(meta, stats)
12
+ name = meta.get_sentence()
13
+ duration_msg = self.get_duration_msg(meta)
14
+ preamble = self.get_preamble('ok', stats.get_count(), meta.get_context())
15
+ self.writer.writeln("#{preamble} ##{name} #{duration_msg}")
16
+ end
17
+
18
+ defm on_spec_failure(meta, err, stats)
19
+ name = meta.get_sentence()
20
+ preamble = self.get_preamble('not ok', stats.get_count(), meta.get_context())
21
+ self.writer.writeln("#{preamble} ##{name} - #{err}")
22
+ end
23
+
24
+ defm on_spec_error(meta, err, stats)
25
+ name = meta.get_sentence()
26
+ preamble = self.get_preamble('not ok', stats.get_count(), meta.get_context())
27
+ self.writer.writeln("#{preamble} ##{name} - #{err}")
28
+ end
29
+
30
+ defm on_spec_pending(meta, stats)
31
+ end
32
+
33
+ defm get_preamble(status, count, context)
34
+ ""status = status . repeat(' ', 6 - len(status))
35
+ msg = "#{status} #{count} - #{context}"
36
+ return msg
37
+ end
38
+ end
@@ -0,0 +1,49 @@
1
+ class Runner
2
+ def initialize()
3
+ self.specs = []
4
+ self.halt = false
5
+ self.stopped = false
6
+ self.bail = false
7
+ end
8
+
9
+ defm set_bail(bail)
10
+ self.bail = bail
11
+ end
12
+
13
+ defm get_bail()
14
+ return self.bail
15
+ end
16
+
17
+ defm add(spec)
18
+ add(self.specs, spec)
19
+ end
20
+
21
+ defm start(reporter, stats)
22
+ reporter.on_start(stats)
23
+
24
+ timer = new SpecTimer()
25
+ timer.start()
26
+
27
+ for spec in self.specs
28
+ if self.stopped
29
+ break
30
+ end
31
+
32
+ spec_runner = new SpecRunner(spec)
33
+ spec_runner.set_bail(self.get_bail())
34
+ spec_runner.start(reporter, stats)
35
+
36
+ if spec_runner.has_bailed()
37
+ self.stopped = true
38
+ end
39
+ end
40
+
41
+ timer.stop()
42
+ reporter.on_end(timer.get_duration(), stats)
43
+ end
44
+
45
+ defm stop()
46
+ self.stopped = true
47
+ end
48
+
49
+ end
@@ -0,0 +1,96 @@
1
+ class SpecRunner
2
+
3
+ def initialize(spec)
4
+ self.spec = spec
5
+ self.stopped = false
6
+ self.bail = false
7
+ self.bailed = false
8
+ end
9
+
10
+ defm set_bail(bail)
11
+ self.bail = bail
12
+ end
13
+
14
+ defm has_bailed()
15
+ return self.bailed
16
+ end
17
+
18
+ defm start(reporter, stats)
19
+ spec = self.spec
20
+ did_fail = false
21
+ context = self.call_hook('describe')
22
+ reporter.on_context_start(context, stats)
23
+ self.call_hook('before')
24
+
25
+ for method in keys(spec)
26
+ if self.stopped
27
+ break
28
+ end
29
+
30
+ if method =~ '^it'
31
+ timer = new SpecTimer()
32
+ meta = new SpecMeta(context, method)
33
+
34
+ reporter.on_spec_start(meta, stats)
35
+ result = 0
36
+
37
+ try
38
+ timer.start()
39
+
40
+ self.call_hook('before_each')
41
+ eval("spec.#{method}()")
42
+ self.call_hook('after_each')
43
+
44
+ timer.stop()
45
+ meta.set_duration(timer.get_duration())
46
+
47
+ stats.inc_passes()
48
+ reporter.on_spec_pass(meta, stats)
49
+ catch /Unknown function.*expect/
50
+ did_fail = true
51
+ stats.inc_failures()
52
+ exception = 'DSLError: expect() not found, dsl.riml may not be included'
53
+ reporter.on_spec_failure(meta, exception, stats)
54
+ catch /Unknown function.*define_matcher/
55
+ did_fail = true
56
+ stats.inc_failures()
57
+ exception = 'DSLError: define_matcher() not found, dsl.riml may not be included'
58
+ reporter.on_spec_failure(meta, exception, stats)
59
+ catch /^AssertionError/
60
+ did_fail = true
61
+ stats.inc_failures()
62
+ reporter.on_spec_failure(meta, v:exception, stats)
63
+ catch /.*/
64
+ did_fail = true
65
+ stats.inc_errors()
66
+ reporter.on_spec_error(meta, v:exception, stats)
67
+ end
68
+
69
+ reporter.on_spec_end(meta, stats)
70
+ :redraw
71
+
72
+ if did_fail && self.bail
73
+ self.bailed = true
74
+ break
75
+ end
76
+ end
77
+ end
78
+
79
+ self.call_hook('after')
80
+ reporter.on_context_end(context, stats)
81
+ end
82
+
83
+ defm call_hook(hook)
84
+ spec = self.spec
85
+ if has_key(spec, hook)
86
+ return eval("spec.#{hook}()");
87
+ else
88
+ return "Undefined hook: #{hook}"
89
+ end
90
+ end
91
+
92
+ defm stop()
93
+ self.stopped = true
94
+ end
95
+
96
+ end
@@ -0,0 +1,18 @@
1
+ module Speckle
2
+ module CLI
3
+
4
+ require_relative 'environment'
5
+ require_relative 'router'
6
+
7
+ class App
8
+ def start(args)
9
+ env = Environment.new
10
+ options = env.load(args)
11
+
12
+ router = Router.new
13
+ router.route(options.action, options)
14
+ end
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,67 @@
1
+ module Speckle
2
+ module CLI
3
+
4
+ require 'speckle/version'
5
+
6
+ class Controller
7
+
8
+ def initialize(options, rake_app)
9
+ @options = options
10
+ @rake_app = rake_app
11
+ end
12
+
13
+ def rake(task)
14
+ @rake_app.invoke_task(task)
15
+ end
16
+
17
+ def show_version
18
+ puts VERSION
19
+ end
20
+
21
+ def show_help
22
+ puts @options.opts
23
+ end
24
+
25
+ def show_error(msg = @options.error)
26
+ puts "Error: #{msg}"
27
+ puts
28
+
29
+ show_help
30
+ end
31
+
32
+ def show_invalid_option
33
+ show_error @options.error
34
+ end
35
+
36
+ def show_missing_args
37
+ show_error @options.error
38
+ end
39
+
40
+ def show_parser_error
41
+ show_error @options.error
42
+ end
43
+
44
+ def show_no_spec_dir
45
+ show_error '"spec" directory not found'
46
+ end
47
+
48
+ def compile
49
+ rake :compile_tests
50
+ end
51
+
52
+ def compile_and_test
53
+ rake :compile_and_test
54
+ end
55
+
56
+ def test
57
+ rake :test
58
+ end
59
+
60
+ def watch
61
+ puts '--- TODO ---'
62
+ end
63
+
64
+ end
65
+
66
+ end
67
+ end