eval_in 0.1.6 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ # This code is mostly tested through tests on the higher level things it depends on
4
+ # But for a few small helpers, I wanted to just hit a lot of edge cases to really
5
+ # give myself confidence they did what I was expecting.
6
+ RSpec.describe EvalIn::HTTP do
7
+ describe '.jsonify_url' do
8
+ def assert_transforms(initial_url, expected_url)
9
+ actual_url = EvalIn::HTTP.jsonify_url initial_url
10
+ expect(actual_url).to eq expected_url
11
+ end
12
+
13
+ it 'appends .json to a url that is missing it' do
14
+ assert_transforms 'http://eval.in/1', 'http://eval.in/1.json'
15
+ assert_transforms 'http://eval.in/1.json', 'http://eval.in/1.json'
16
+
17
+ assert_transforms 'http://eval.in/1?a=b', 'http://eval.in/1.json?a=b'
18
+ assert_transforms 'http://eval.in/1.json?a=b', 'http://eval.in/1.json?a=b'
19
+ end
20
+
21
+ it 'changes .not-json to .json' do
22
+ assert_transforms 'http://eval.in/1.xml', 'http://eval.in/1.json'
23
+ assert_transforms 'http://eval.in/1.html', 'http://eval.in/1.json'
24
+ assert_transforms 'http://eval.in/1.html?a=b', 'http://eval.in/1.json?a=b'
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,168 @@
1
+ require 'spec_helper'
2
+ require 'eval_in/mock'
3
+
4
+
5
+ # TODO: look at other reasons the thing could blow up, do we need to provide the mock a way to do these things?
6
+ RSpec.describe EvalIn::Mock do
7
+ def is_jruby?
8
+ defined? RUBY_ENGINE and RUBY_ENGINE == 'jruby'
9
+ end
10
+
11
+ specify 'instances provide the same methods with the same signatures as the EvalIn class' do
12
+ mock = described_class.new
13
+ EvalIn.methods(false).each do |method_name|
14
+ expected_signature = EvalIn.method(method_name).parameters
15
+ actual_signature = mock.method(method_name).parameters
16
+ expect(actual_signature).to eq expected_signature
17
+ end
18
+ end
19
+
20
+ describe '#call' do
21
+ context 'when initialized with a mock result' do
22
+ it 'returns the mock result' do
23
+ result = Object.new
24
+ mock = described_class.new result: result
25
+ expect(mock.call "code", language: '').to equal result
26
+ end
27
+ it 'raises an ArgumentError if no language is provided' do
28
+ mock = described_class.new result: Object.new
29
+ expect { mock.call "code" }.to raise_error ArgumentError
30
+ expect { mock.call "code", language: '' }.to_not raise_error
31
+ end
32
+ end
33
+
34
+ context 'when initialized with an on_call proc' do
35
+ it 'passes the code and options to the proc and returns the result' do
36
+ mock = described_class.new on_call: -> code, options {
37
+ expect(code).to eq 'on_call code'
38
+ expect(options).to eq language: 'l'
39
+ 123
40
+ }
41
+ expect(mock.call "on_call code", language: "l").to eq 123
42
+ end
43
+
44
+ it 'raises an ArgumentError if no language is provided' do
45
+ mock = described_class.new on_call: -> * {}
46
+ expect { mock.call "code" }.to raise_error ArgumentError
47
+ expect { mock.call "code", language: '' }.to_not raise_error
48
+ end
49
+ end
50
+
51
+ context 'when initialized without a a result or on_call proc' do
52
+ before do
53
+ if is_jruby?
54
+ pending "I can't figure out how to get JRuby to execute a fucking process"
55
+ raise "Why did RSpec remove the block form of pending?"
56
+ end
57
+ end
58
+
59
+ it 'executes the code with open3 against the list of language mappings' do
60
+ mock = described_class.new(languages: {
61
+ 'correct-lang' => {program: 'echo', args: ['RIGHT LANGUAGE']},
62
+ 'incorrect-lang' => {program: 'echo', args: ['WRONG LANGUAGE']},
63
+ })
64
+ result = mock.call 'some code', language: 'correct-lang'
65
+ expect(result.output).to start_with 'RIGHT LANGUAGE'
66
+ end
67
+
68
+ def result_from(options={})
69
+ language = options.fetch :language, 'dummy language'
70
+ code = options.fetch :code, 'dummy code'
71
+ program_code = options.fetch :program_code, '# noop'
72
+
73
+ described_class.new(languages: {
74
+ language => {
75
+ program: RbConfig.ruby,
76
+ args: ['-e', program_code]
77
+ }
78
+ }).call(code, language: language)
79
+ end
80
+
81
+ it 'records stderr and stdout' do
82
+ result = result_from program_code: '$stdout.print("STDOUT "); $stdout.flush; $stderr.print("STDERR")'
83
+ expect(result.output).to eq 'STDOUT STDERR'
84
+ end
85
+
86
+ it 'records the exit status' do
87
+ expect(result_from(program_code: 'exit 12').exitstatus).to eq 12
88
+ expect(result_from(program_code: 'exit 99').exitstatus).to eq 99
89
+ end
90
+
91
+ it 'sets the language and language_friendly to the provided language' do
92
+ result = result_from language: 'the-lang'
93
+ expect(result.language).to eq 'the-lang'
94
+ expect(result.language_friendly).to eq 'the-lang'
95
+ end
96
+
97
+ it 'sets the code to the provided code' do
98
+ expect(result_from(code: 'the-code').code).to eq 'the-code'
99
+ end
100
+
101
+ it 'sets the url to my mock result at https://eval.in/207744.json' do
102
+ expect(result_from().url).to eq 'https://eval.in/207744.json'
103
+ end
104
+
105
+ it 'sets the status to something looking like a real status' do
106
+ # in this case, just the status from https://eval.in/207744.json
107
+ expect(result_from().status).to match success_status_regex
108
+ end
109
+
110
+ it 'blows up if asked for a language it doesn\'t know how to evaluate' do
111
+ expect { described_class.new.call '', language: 'no-such-lang' }
112
+ .to raise_error KeyError, /no-such-lang/
113
+ end
114
+
115
+ it 'raises an ArgumentError if no language is provided' do
116
+ mock = described_class.new languages: {'l' => {program: 'echo', args: []}}
117
+ expect { mock.call "code" }.to raise_error ArgumentError
118
+ expect { mock.call "code", language: 'l' }.to_not raise_error
119
+ end
120
+ end
121
+ end
122
+
123
+ describe '#fetch_result' do
124
+ context 'when initialized with a mock result' do
125
+ it 'returns the mock result' do
126
+ result = Object.new
127
+ mock = described_class.new(result: result)
128
+ expect(mock.fetch_result "code").to equal result
129
+ end
130
+ end
131
+
132
+ context 'when initialized with an on_fetch_result proc' do
133
+ it 'passes the url and options to the proc and returns the result' do
134
+ mock = described_class.new on_fetch_result: -> url, options {
135
+ expect(url).to eq 'some url'
136
+ expect(options).to eq a: 'b'
137
+ 123
138
+ }
139
+ expect(mock.fetch_result 'some url', a: 'b').to eq 123
140
+ end
141
+ end
142
+
143
+ context 'when initialized without a result or on_fetch_result proc' do
144
+ include WebMock::API
145
+
146
+ it 'delegates to the real implementation' do
147
+ url = "http://example.com/some-result.json"
148
+ result_hash = {'lang_friendly' => 'some lang friendly',
149
+ 'lang' => 'some lang',
150
+ 'code' => 'some code',
151
+ 'output' => 'some output',
152
+ 'status' => 'some status'}
153
+ stub_request(:get, url)
154
+ .with(headers: {'User-Agent' => 'http://rubygems.org/gems/eval_in (context)'})
155
+ .to_return(status: 200, body: JSON.dump(result_hash))
156
+ result = described_class.new.fetch_result("http://example.com/some-result.json", context: 'context')
157
+ assert_result result,
158
+ exitstatus: 0,
159
+ language: result_hash['lang'],
160
+ language_friendly: result_hash['lang_friendly'],
161
+ code: result_hash['code'],
162
+ output: result_hash['output'],
163
+ status: result_hash['status'],
164
+ url: url
165
+ end
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,93 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe EvalIn::Result do
4
+ it 'initializes with the provided attributes' do
5
+ result = EvalIn::Result.new exitstatus: 123,
6
+ language: 'the language',
7
+ language_friendly: 'the friendly language',
8
+ code: 'the code',
9
+ output: 'the output',
10
+ status: 'the status'
11
+ assert_result result,
12
+ exitstatus: 123,
13
+ language: 'the language',
14
+ language_friendly: 'the friendly language',
15
+ code: 'the code',
16
+ output: 'the output',
17
+ status: 'the status'
18
+ end
19
+
20
+ it 'uses sensible type-correct defaults for missing attributes' do
21
+ assert_result EvalIn::Result.new,
22
+ exitstatus: -1,
23
+ language: '',
24
+ language_friendly: '',
25
+ code: '',
26
+ output: '',
27
+ status: '',
28
+ url: ''
29
+ assert_result EvalIn::Result.new(language: nil,
30
+ language_friendly: nil,
31
+ code: nil,
32
+ output: nil,
33
+ status: nil,
34
+ url: nil),
35
+ exitstatus: -1,
36
+ language: '',
37
+ language_friendly: '',
38
+ code: '',
39
+ output: '',
40
+ status: '',
41
+ url: ''
42
+ end
43
+
44
+ it 'doesn\'t mutate the input attributes' do
45
+ attributes = {status: 'OK'}
46
+ EvalIn::Result.new attributes
47
+ expect(attributes).to eq status: 'OK'
48
+ end
49
+
50
+ it 'logs extra attributes to stderr input' do
51
+ fake_error_stream = StringIO.new
52
+ EvalIn::Result.new a: 1, b: 2, stderr: fake_error_stream
53
+ expect(fake_error_stream.string).to eq "Unexpected attributes! [:a, :b]\n"
54
+ end
55
+
56
+ it 'defaults the error stream to $stderr' do
57
+ expect { EvalIn::Result.new a: 1, b: 2 }.to \
58
+ output("Unexpected attributes! [:a, :b]\n").to_stderr
59
+ end
60
+
61
+ it 'has an as_json representation which dumps all its keys' do
62
+ result = EvalIn::Result.new(language: 'l',
63
+ language_friendly: 'lf',
64
+ code: 'c',
65
+ output: 'o',
66
+ status: 's',
67
+ url: 'u')
68
+ expect(result.as_json).to eq 'exitstatus' => -1,
69
+ 'language' => 'l',
70
+ 'language_friendly' => 'lf',
71
+ 'code' => 'c',
72
+ 'output' => 'o',
73
+ 'status' => 's',
74
+ 'url' => 'u'
75
+ end
76
+
77
+ it 'has a to_json that works correctly' do
78
+ result = EvalIn::Result.new(language: 'l',
79
+ language_friendly: 'lf',
80
+ code: 'c',
81
+ output: 'o',
82
+ status: 's',
83
+ url: 'u')
84
+ after_json = JSON.parse(result.to_json)
85
+ expect(after_json).to eq 'exitstatus' => -1,
86
+ 'language' => 'l',
87
+ 'language_friendly' => 'lf',
88
+ 'code' => 'c',
89
+ 'output' => 'o',
90
+ 'status' => 's',
91
+ 'url' => 'u'
92
+ end
93
+ end
@@ -0,0 +1,23 @@
1
+ require 'eval_in'
2
+ require 'webmock'
3
+ WebMock.disable_net_connect!
4
+
5
+ RSpec.configure do |config|
6
+ config.filter_run_excluding integration: true
7
+
8
+ config.include Module.new {
9
+ def assert_result(result, attributes)
10
+ attributes.each do |key, value|
11
+ expect(result.public_send key).to eq value
12
+ end
13
+ end
14
+
15
+ def success_status_regex
16
+ /OK \([\d.]+ sec real, [\d.]+ sec wall, \d MB, \d+ syscalls\)/
17
+ end
18
+ }
19
+
20
+ config.after do
21
+ WebMock.reset!
22
+ end
23
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eval_in
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Cheek
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-06 00:00:00.000000000 Z
11
+ date: 2014-10-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -79,8 +79,17 @@ files:
79
79
  - Readme.md
80
80
  - eval_in.gemspec
81
81
  - lib/eval_in.rb
82
- - lib/eval_in/version.rb
82
+ - lib/eval_in/client.rb
83
+ - lib/eval_in/constants.rb
84
+ - lib/eval_in/http.rb
85
+ - lib/eval_in/mock.rb
86
+ - lib/eval_in/result.rb
87
+ - spec/client_spec.rb
83
88
  - spec/eval_in_spec.rb
89
+ - spec/http_spec.rb
90
+ - spec/mock_spec.rb
91
+ - spec/result_spec.rb
92
+ - spec/spec_helper.rb
84
93
  homepage: https://github.com/JoshCheek/eval_in
85
94
  licenses:
86
95
  - WTFPL
@@ -106,5 +115,10 @@ signing_key:
106
115
  specification_version: 4
107
116
  summary: Evaluates code (Ruby and others) safely by sending it to https://eval.in
108
117
  test_files:
118
+ - spec/client_spec.rb
109
119
  - spec/eval_in_spec.rb
120
+ - spec/http_spec.rb
121
+ - spec/mock_spec.rb
122
+ - spec/result_spec.rb
123
+ - spec/spec_helper.rb
110
124
  has_rdoc:
@@ -1,3 +0,0 @@
1
- module EvalIn
2
- VERSION = '0.1.6'
3
- end