jsonapi-grader 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/jsonapi-grader +10 -1
- data/lib/jsonapi/grader/serialization_grader.rb +64 -0
- data/lib/jsonapi/grader/server/scenarii/empty_collection.rb +45 -0
- data/lib/jsonapi/grader/server/scenarii.rb +1 -0
- data/lib/jsonapi/grader/server/scenario.rb +31 -0
- data/lib/jsonapi/grader/server_grader.rb +41 -0
- data/lib/jsonapi/grader.rb +2 -63
- data/{scenarii.json → scenarii_serialization.json} +0 -0
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 36b447ba1230dd7ab8e6c1546ed576c0bf559c29
|
4
|
+
data.tar.gz: 9b28cc55cb678ce74d91a2e1d44ac02cc0154c14
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ab4280c8cc133cf54a8169c26b247ef290d818a0d745533a451222d8d54b4600c557c6b3e0a0d96f24bce641dc8bc3626bdc8b3c50a7ca0f0771a8ab260ffc5a
|
7
|
+
data.tar.gz: d20412c5bb6b74c1c1470bf5704c64c2b3b072ede3068aa8154d06360f5107ca24aae1be33a4f003c4ffcb2a210f2a48bbf0c5f2fd2034fb6555e72d35ec923b
|
data/bin/jsonapi-grader
CHANGED
@@ -2,6 +2,15 @@
|
|
2
2
|
|
3
3
|
require 'jsonapi/grader'
|
4
4
|
|
5
|
-
grader =
|
5
|
+
grader =
|
6
|
+
case ARGV[0]
|
7
|
+
when 'serialization'
|
8
|
+
JSONAPI::Grader::SerializationGrader.new('scenarii_serialization.json',
|
9
|
+
implementation_dir: ARGV[1])
|
10
|
+
when 'server'
|
11
|
+
JSONAPI::Grader::ServerGrader.new(host: ARGV[1])
|
12
|
+
else
|
13
|
+
raise 'Unknown arguments'
|
14
|
+
end
|
6
15
|
|
7
16
|
grader.grade
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module JSONAPI
|
4
|
+
module Grader
|
5
|
+
class SerializationGrader
|
6
|
+
def initialize(scenarii_file = 'scenarii_serialization.json', options = {})
|
7
|
+
scenarii_file = File.expand_path("../../../#{scenarii_file}", __dir__)
|
8
|
+
@scenarii = JSON.parse(File.read(scenarii_file))
|
9
|
+
@implementation_dir = options[:implementation_dir]
|
10
|
+
end
|
11
|
+
|
12
|
+
def grade
|
13
|
+
compliance = true
|
14
|
+
score = 0
|
15
|
+
max_score = 0
|
16
|
+
@scenarii.each do |scenario|
|
17
|
+
current_score = score_scenario(scenario)
|
18
|
+
compliance = false if scenario['required'] && current_score == 0
|
19
|
+
max_score += scenario['score']
|
20
|
+
score += current_score
|
21
|
+
end
|
22
|
+
|
23
|
+
STDERR.puts "Compliance: #{compliance}"
|
24
|
+
score_percent = (100.0 * score / max_score).round(2)
|
25
|
+
STDERR.puts "Score: #{score} / #{max_score} (#{score_percent}%)"
|
26
|
+
|
27
|
+
score
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def score_scenario(scenario)
|
33
|
+
document_file = File.expand_path("../../../#{scenario['file']}", __dir__)
|
34
|
+
reference_document = normalize(JSON.parse(File.read(document_file)))
|
35
|
+
implementation = "#{@implementation_dir}/#{scenario['name']}"
|
36
|
+
STDERR.print "Running scenario #{scenario['name']}... "
|
37
|
+
$stderr.flush
|
38
|
+
unless File.exists?(implementation)
|
39
|
+
STDERR.puts "not implemented"
|
40
|
+
return 0
|
41
|
+
end
|
42
|
+
|
43
|
+
actual_document = normalize(JSON.parse(`#{implementation}`))
|
44
|
+
if reference_document == actual_document
|
45
|
+
STDERR.puts "passed"
|
46
|
+
return scenario['score']
|
47
|
+
else
|
48
|
+
STDERR.puts "failed"
|
49
|
+
STDERR.puts "Expected: #{reference_document}"
|
50
|
+
STDERR.puts "Got: #{actual_document}"
|
51
|
+
return 0
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def normalize(document)
|
56
|
+
return document unless document.key?('included')
|
57
|
+
|
58
|
+
document['included'].sort do |a, b|
|
59
|
+
[a['type'], a['id']] <=> [b['type'], b['id']]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'jsonapi/grader/server/scenario'
|
3
|
+
|
4
|
+
module JSONAPI
|
5
|
+
module Grader
|
6
|
+
module Server
|
7
|
+
class EmptyCollectionScenario < Scenario
|
8
|
+
def name
|
9
|
+
'empty_collection'
|
10
|
+
end
|
11
|
+
|
12
|
+
def description
|
13
|
+
'The endpoint /empty_collection should return an empty collection.'
|
14
|
+
end
|
15
|
+
|
16
|
+
def score
|
17
|
+
100
|
18
|
+
end
|
19
|
+
|
20
|
+
def required
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
24
|
+
def call(host)
|
25
|
+
uri = URI("#{host}/empty_collection")
|
26
|
+
res = Net::HTTP.start(uri.hostname, uri.port) do |http|
|
27
|
+
req = Net::HTTP::Get.new(uri)
|
28
|
+
req['Accept'] = 'application/vnd.api+json'
|
29
|
+
|
30
|
+
http.request(req)
|
31
|
+
end
|
32
|
+
|
33
|
+
unless res['Content-Type'] == 'application/vnd.api+json'
|
34
|
+
fail 'Expected Content-Type header to equal application/vnd.api+json'
|
35
|
+
end
|
36
|
+
|
37
|
+
body = JSON.parse(res.body)
|
38
|
+
unless body['data'] == []
|
39
|
+
fail 'Expected empty collection'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'jsonapi/grader/server/scenarii/empty_collection'
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module JSONAPI
|
2
|
+
module Grader
|
3
|
+
module Server
|
4
|
+
class Scenario
|
5
|
+
def call(host)
|
6
|
+
raise 'Not implemented'
|
7
|
+
end
|
8
|
+
|
9
|
+
def score
|
10
|
+
raise 'Not implemented'
|
11
|
+
end
|
12
|
+
|
13
|
+
def name
|
14
|
+
raise 'Not implemented'
|
15
|
+
end
|
16
|
+
|
17
|
+
def description
|
18
|
+
raise 'Not implemented'
|
19
|
+
end
|
20
|
+
|
21
|
+
def endpoint
|
22
|
+
raise 'Not implemented'
|
23
|
+
end
|
24
|
+
|
25
|
+
def required
|
26
|
+
raise 'Not implemented'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'jsonapi/grader/server/scenarii'
|
2
|
+
|
3
|
+
module JSONAPI
|
4
|
+
module Grader
|
5
|
+
class ServerGrader
|
6
|
+
SCENARII = [Server::EmptyCollectionScenario.new]
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
@host = options[:host]
|
10
|
+
end
|
11
|
+
|
12
|
+
def grade
|
13
|
+
compliance = true
|
14
|
+
score = 0
|
15
|
+
max_score = 0
|
16
|
+
SCENARII.each do |scenario|
|
17
|
+
STDERR.print "Running scenario #{scenario.name}... "
|
18
|
+
$stderr.flush
|
19
|
+
|
20
|
+
begin
|
21
|
+
scenario.call(@host)
|
22
|
+
STDERR.puts "passed"
|
23
|
+
score += scenario.score
|
24
|
+
rescue Exception => error
|
25
|
+
STDERR.puts "failed"
|
26
|
+
STDERR.puts scenario.description
|
27
|
+
STDERR.puts ">>> #{error}"
|
28
|
+
compliance = false if scenario.required
|
29
|
+
end
|
30
|
+
max_score += scenario.score
|
31
|
+
end
|
32
|
+
|
33
|
+
STDERR.puts "Compliance: #{compliance}"
|
34
|
+
score_percent = (100.0 * score / max_score).round(2)
|
35
|
+
STDERR.puts "Score: #{score} / #{max_score} (#{score_percent}%)"
|
36
|
+
|
37
|
+
score
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/jsonapi/grader.rb
CHANGED
@@ -1,63 +1,2 @@
|
|
1
|
-
require '
|
2
|
-
|
3
|
-
module JSONAPI
|
4
|
-
class Grader
|
5
|
-
def initialize(implementation_dir)
|
6
|
-
@implementation_dir = implementation_dir
|
7
|
-
scenarii_file = File.dirname(__FILE__) + '/../../scenarii.json'
|
8
|
-
@scenarii = JSON.parse(File.read(scenarii_file))
|
9
|
-
end
|
10
|
-
|
11
|
-
def grade
|
12
|
-
compliance = true
|
13
|
-
score = 0
|
14
|
-
max_score = 0
|
15
|
-
@scenarii.each do |scenario|
|
16
|
-
current_score = score_scenario(scenario)
|
17
|
-
compliance = false if scenario['required'] && current_score == 0
|
18
|
-
max_score += scenario['score']
|
19
|
-
score += current_score
|
20
|
-
end
|
21
|
-
|
22
|
-
STDERR.puts "Compliance: #{compliance}"
|
23
|
-
score_percent = (100.0 * score / max_score).round(2)
|
24
|
-
STDERR.puts "Score: #{score} / #{max_score} (#{score_percent}%)"
|
25
|
-
|
26
|
-
score
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
def score_scenario(scenario)
|
32
|
-
document_file = File.dirname(__FILE__) + "/../../#{scenario['file']}"
|
33
|
-
reference_document = normalize(JSON.parse(File.read(document_file)))
|
34
|
-
implementation = "#{@implementation_dir}/#{scenario['name']}"
|
35
|
-
STDERR.print "Running scenario #{scenario['name']}... "
|
36
|
-
$stderr.flush
|
37
|
-
unless File.exists?(implementation)
|
38
|
-
STDERR.puts "not implemented"
|
39
|
-
return 0
|
40
|
-
end
|
41
|
-
|
42
|
-
actual_document = normalize(JSON.parse(`#{implementation}`))
|
43
|
-
if reference_document == actual_document
|
44
|
-
STDERR.puts "passed"
|
45
|
-
return scenario['score']
|
46
|
-
else
|
47
|
-
STDERR.puts "failed"
|
48
|
-
STDERR.puts "Expected: #{reference_document}"
|
49
|
-
STDERR.puts "Got: #{actual_document}"
|
50
|
-
$stderr.flush
|
51
|
-
return 0
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def normalize(document)
|
56
|
-
return document unless document.key?('included')
|
57
|
-
|
58
|
-
document['included'].sort do |a, b|
|
59
|
-
[a['type'], a['id']] <=> [b['type'], b['id']]
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
1
|
+
require 'jsonapi/grader/serialization_grader'
|
2
|
+
require 'jsonapi/grader/server_grader'
|
File without changes
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsonapi-grader
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lucas Hosseini
|
@@ -17,6 +17,12 @@ executables:
|
|
17
17
|
extensions: []
|
18
18
|
extra_rdoc_files: []
|
19
19
|
files:
|
20
|
+
- "./lib/jsonapi/grader.rb"
|
21
|
+
- "./lib/jsonapi/grader/serialization_grader.rb"
|
22
|
+
- "./lib/jsonapi/grader/server/scenarii.rb"
|
23
|
+
- "./lib/jsonapi/grader/server/scenarii/empty_collection.rb"
|
24
|
+
- "./lib/jsonapi/grader/server/scenario.rb"
|
25
|
+
- "./lib/jsonapi/grader/server_grader.rb"
|
20
26
|
- "./scenarii/empty_collection.json"
|
21
27
|
- "./scenarii/null_data.json"
|
22
28
|
- "./scenarii/simple_resource.json"
|
@@ -24,8 +30,7 @@ files:
|
|
24
30
|
- "./scenarii/simple_resource_jsonapi_object.json"
|
25
31
|
- "./scenarii/simple_resource_meta.json"
|
26
32
|
- bin/jsonapi-grader
|
27
|
-
-
|
28
|
-
- scenarii.json
|
33
|
+
- scenarii_serialization.json
|
29
34
|
homepage: https://github.com/beauby/jsonapi-grader
|
30
35
|
licenses:
|
31
36
|
- MIT
|