smartring 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +53 -0
- data/bin/bundle +103 -0
- data/bin/byebug +29 -0
- data/bin/coderay +29 -0
- data/bin/dotenv +29 -0
- data/bin/httparty +29 -0
- data/bin/listen +29 -0
- data/bin/nokogiri +29 -0
- data/bin/pry +29 -0
- data/bin/rackup +29 -0
- data/bin/rake +29 -0
- data/bin/rerun +29 -0
- data/bin/rubocop +29 -0
- data/bin/ruby-parse +29 -0
- data/bin/ruby-rewrite +29 -0
- data/bin/safe_yaml +29 -0
- data/bin/smartring +29 -0
- data/exe/smartring +7 -0
- data/lib/smartling/auth.rb +61 -0
- data/lib/smartling/client.rb +36 -0
- data/lib/smartling/contexts.rb +76 -0
- data/lib/smartling/files.rb +50 -0
- data/lib/smartling/strings.rb +31 -0
- data/lib/smartling/verbs.rb +17 -0
- data/lib/smartling.rb +14 -0
- data/lib/smartring.rb +3 -0
- data/test/smartling/auth_test.rb +24 -0
- data/test/smartling/client_test.rb +33 -0
- data/test/smartling/contexts_test.rb +119 -0
- data/test/smartling/files_test.rb +78 -0
- data/test/smartling/strings_test.rb +26 -0
- data/test/smartling_test.rb +16 -0
- data/test/test_helper.rb +26 -0
- metadata +319 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'httmultiparty'
|
4
|
+
require 'hipsterhash'
|
5
|
+
|
6
|
+
module Smartling
|
7
|
+
# Methods for authenticating a Smartling user with the API.
|
8
|
+
module Auth
|
9
|
+
attr_reader :user_id, :user_secret, :access_token, :refresh_token
|
10
|
+
|
11
|
+
def authenticate
|
12
|
+
refresh_token! if access_token&.expired? && refresh_token&.valid?
|
13
|
+
authenticate! unless access_token&.valid?
|
14
|
+
token = access_token.to_s
|
15
|
+
return token unless block_given?
|
16
|
+
yield token
|
17
|
+
end
|
18
|
+
|
19
|
+
public
|
20
|
+
|
21
|
+
def refresh_token!
|
22
|
+
path = '/auth-api/v2/authenticate/refresh'
|
23
|
+
headers = { 'Content-Type' => 'application/json' }
|
24
|
+
payload = { refreshToken: refresh_token.to_s }.to_json
|
25
|
+
resp = self.class.post(path, headers: headers, query: payload)
|
26
|
+
resp = HipsterHash[resp.parsed_response].response
|
27
|
+
raise(Failed, resp) unless resp.code == 'SUCCESS'
|
28
|
+
self.tokens = resp.data
|
29
|
+
true
|
30
|
+
end
|
31
|
+
|
32
|
+
def authenticate!
|
33
|
+
path = '/auth-api/v2/authenticate'
|
34
|
+
payload = { userIdentifier: user_id, userSecret: user_secret }.to_json
|
35
|
+
headers = { 'Content-Type' => 'application/json' }
|
36
|
+
resp = self.class.post(path, headers: headers, body: payload)
|
37
|
+
resp = HipsterHash[resp.parsed_response].response
|
38
|
+
raise(Failed, resp) unless resp.code == 'SUCCESS'
|
39
|
+
self.tokens = resp.data
|
40
|
+
true
|
41
|
+
end
|
42
|
+
|
43
|
+
def tokens=(data)
|
44
|
+
@access_token = Token.new(data.accessToken, data.expiresIn)
|
45
|
+
@refresh_token = Token.new(data.refreshToken, data.refreshExpiresIn)
|
46
|
+
end
|
47
|
+
|
48
|
+
Token = Class.new do
|
49
|
+
def initialize(token, expires_in)
|
50
|
+
@token = token
|
51
|
+
@expires_at = Time.now + expires_in
|
52
|
+
end
|
53
|
+
define_method(:expired?) { @expires_at < Time.now }
|
54
|
+
define_method(:valid?) { !expired? }
|
55
|
+
define_method(:to_s) { @token.to_s }
|
56
|
+
end
|
57
|
+
|
58
|
+
Error = Class.new(Exception)
|
59
|
+
Failed = Class.new(Error)
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'smartling/auth'
|
5
|
+
require 'smartling/files'
|
6
|
+
require 'smartling/contexts'
|
7
|
+
require 'smartling/strings'
|
8
|
+
require 'smartling/verbs'
|
9
|
+
require 'hipsterhash'
|
10
|
+
require 'forwardable'
|
11
|
+
|
12
|
+
module Smartling
|
13
|
+
# A fairly generic Smartling REST API client.
|
14
|
+
class Client
|
15
|
+
include HTTMultiParty
|
16
|
+
include Auth
|
17
|
+
include Files
|
18
|
+
include Strings
|
19
|
+
include Contexts
|
20
|
+
include Verbs
|
21
|
+
|
22
|
+
attr_accessor :project_id
|
23
|
+
|
24
|
+
base_uri 'https://api.smartling.com'
|
25
|
+
headers 'Accept' => 'application/json'
|
26
|
+
raise_on [404, 401, 500]
|
27
|
+
|
28
|
+
def initialize(user_id: ENV.fetch('SMARTLING_USER_ID'),
|
29
|
+
user_secret: ENV.fetch('SMARTLING_USER_SECRET'),
|
30
|
+
project_id: ENV.fetch('SMARTLING_PROJECT_ID', nil))
|
31
|
+
@user_id = user_id
|
32
|
+
@user_secret = user_secret
|
33
|
+
@project_id = project_id
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Smartling
|
4
|
+
# Methods for dealing wth the Smartling Contexts API
|
5
|
+
module Contexts
|
6
|
+
def contexts(project_id: @project_id, name_filter: nil, offset: nil,
|
7
|
+
type: nil)
|
8
|
+
path = "/context-api/v2/projects/#{project_id}/contexts"
|
9
|
+
query = {}
|
10
|
+
query[:nameFilter] = name_filter unless name_filter.nil?
|
11
|
+
query[:offset] = Integer(offset) unless offset.nil?
|
12
|
+
query[:type] = type.to_s.upcase unless type.nil?
|
13
|
+
get(path, query: query)
|
14
|
+
end
|
15
|
+
|
16
|
+
def context(project_id: @project_id, context_uid:)
|
17
|
+
path = "/context-api/v2/projects/#{project_id}/contexts/#{context_uid}"
|
18
|
+
get(path)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Uploads a new context. Content must quack like an UploadIO.
|
22
|
+
def upload_context(project_id: @project_id, content:, name: nil)
|
23
|
+
path = "/context-api/v2/projects/#{project_id}/contexts"
|
24
|
+
raise(InvalidContent, content) unless Contexts.valid_content?(content)
|
25
|
+
body = { content: content }
|
26
|
+
body[:name] = name unless name.nil?
|
27
|
+
post(path, body: body)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Uploads a new context. Content must quack like an UploadIO.
|
31
|
+
def upload_context_and_match(project_id: @project_id, content:,
|
32
|
+
match_params: nil, name: nil)
|
33
|
+
path = "/context-api/v2/projects/#{project_id}/contexts"
|
34
|
+
path += '/upload-and-match-async'
|
35
|
+
raise(InvalidContent, content) unless Contexts.valid_content?(content)
|
36
|
+
body = { content: content }
|
37
|
+
body[:name] = name unless name.nil?
|
38
|
+
body[:matchParams] = match_params unless match_params.nil?
|
39
|
+
post(path, body: body)
|
40
|
+
end
|
41
|
+
|
42
|
+
def download_context(project_id: @project_id, context_uid:)
|
43
|
+
path = "/context-api/v2/projects/#{project_id}/contexts"
|
44
|
+
path += "/#{context_uid}/content"
|
45
|
+
get(path)
|
46
|
+
end
|
47
|
+
|
48
|
+
def delete_context(project_id: @project_id, context_uid:)
|
49
|
+
path = "/context-api/v2/projects/#{project_id}/contexts/#{context_uid}"
|
50
|
+
delete(path)
|
51
|
+
end
|
52
|
+
|
53
|
+
# POSTs to the /match/async endpoint
|
54
|
+
def match_context(project_id: @project_id, context_uid:, hashcodes: [])
|
55
|
+
path = "/context-api/v2/projects/#{project_id}/contexts/#{context_uid}"
|
56
|
+
path += '/match/async'
|
57
|
+
query = { stringHashcodes: hashcodes }.to_json
|
58
|
+
headers = { 'Content-Type' => 'application/json' }
|
59
|
+
post(path, query: query, headers: headers)
|
60
|
+
end
|
61
|
+
|
62
|
+
# GETs the results of an async match
|
63
|
+
def context_matches(project_id: @project_id, match_id:)
|
64
|
+
path = "/context-api/v2/projects/#{project_id}/match/#{match_id}"
|
65
|
+
get(path)
|
66
|
+
end
|
67
|
+
|
68
|
+
InvalidContent = Class.new(ArgumentError)
|
69
|
+
|
70
|
+
def self.valid_content?(content)
|
71
|
+
%i[read content_type original_filename].all? do |required_method|
|
72
|
+
content.respond_to?(required_method)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'time'
|
4
|
+
require 'net/http/post/multipart'
|
5
|
+
|
6
|
+
module Smartling
|
7
|
+
# Methods for using the Smartling files API
|
8
|
+
module Files
|
9
|
+
def files(project_id: @project_id)
|
10
|
+
path = "/files-api/v2/projects/#{project_id}/files/list"
|
11
|
+
get(path)
|
12
|
+
end
|
13
|
+
|
14
|
+
def file(project_id: @project_id, file_uri:, locale: nil)
|
15
|
+
path = ["/files-api/v2/projects/#{project_id}"]
|
16
|
+
path << "locales/#{locale}" unless locale.nil?
|
17
|
+
path << 'file/status'
|
18
|
+
path = path.join('/')
|
19
|
+
get(path, query: { fileUri: file_uri })
|
20
|
+
end
|
21
|
+
|
22
|
+
def delete_file(project_id: @project_id, file_uri:)
|
23
|
+
path = "/files-api/v2/projects/#{project_id}/file/delete"
|
24
|
+
post(path, body: { fileUri: file_uri })
|
25
|
+
end
|
26
|
+
|
27
|
+
def upload_file(project_id: @project_id, file:, file_uri:, file_type:,
|
28
|
+
callback: nil, authorize: nil, locales_to_authorize: nil,
|
29
|
+
smartling: {})
|
30
|
+
raise(InvalidFile, file) unless Files.valid_file?(file)
|
31
|
+
path = "/files-api/v2/projects/#{project_id}/file"
|
32
|
+
body = { file: file, fileUri: file_uri, fileType: file_type }
|
33
|
+
body[:authorize] = authorize unless authorize.nil?
|
34
|
+
body[:callback] = callback unless callback.nil?
|
35
|
+
unless locales_to_authorize.nil?
|
36
|
+
body[:localeIdsToAuthorize] = locales_to_authorize
|
37
|
+
end
|
38
|
+
smartling.each { |k, v| body["smartling.#{k}"] = v }
|
39
|
+
post(path, body: body)
|
40
|
+
end
|
41
|
+
|
42
|
+
InvalidFile = Class.new(ArgumentError)
|
43
|
+
|
44
|
+
def self.valid_file?(content)
|
45
|
+
%i[read content_type original_filename].all? do |required_method|
|
46
|
+
content.respond_to?(required_method)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Smartling
|
4
|
+
# Methods for the Smartling strings API
|
5
|
+
module Strings
|
6
|
+
def source_strings(project_id: @project_id, file_uri: nil, hashcodes: nil,
|
7
|
+
limit: nil, offset: nil)
|
8
|
+
path = "/strings-api/v2/projects/#{project_id}/source-strings"
|
9
|
+
query = {}
|
10
|
+
query[:fileUri] = file_uri unless file_uri.nil?
|
11
|
+
query[:stringHashcodes] = hashcodes unless hashcodes.nil?
|
12
|
+
query[:limit] = Integer(limit) unless limit.nil?
|
13
|
+
query[:offset] = Integer(offset) unless limit.nil?
|
14
|
+
get(path, query: query)
|
15
|
+
end
|
16
|
+
|
17
|
+
def translations(project_id: @project_id, file_uri: nil, hashcodes: nil,
|
18
|
+
limit: nil, offset: nil, retrieval_type: nil,
|
19
|
+
target_locale_id: nil)
|
20
|
+
path = "/strings-api/v2/projects/#{project_id}/translations"
|
21
|
+
query = {}
|
22
|
+
query[:fileUri] = file_uri unless file_uri.nil?
|
23
|
+
query[:hashcodes] = hashcodes unless hashcodes.nil?
|
24
|
+
query[:retrievalType] = retrieval_type unless retrieval_type.nil?
|
25
|
+
query[:limit] = Integer(limit) unless limit.nil?
|
26
|
+
query[:offset] = Integer(offset) unless limit.nil?
|
27
|
+
query[:targetLocaleId] = target_locale_id unless target_locale_id.nil?
|
28
|
+
get(path, query: query)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Smartling
|
5
|
+
module Verbs
|
6
|
+
%i[get put post patch delete].each do |verb|
|
7
|
+
define_method(verb) do |path, options = {}|
|
8
|
+
authenticate do |token|
|
9
|
+
(options[:headers] ||= {})[:Authorization] = "Bearer #{token}"
|
10
|
+
resp = self.class.send(verb, path, options).parsed_response
|
11
|
+
return resp unless resp.is_a?(Hash)
|
12
|
+
HipsterHash[resp].response
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/smartling.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'smartling/client'
|
4
|
+
|
5
|
+
# Smartling contains a client and helpers for working with the Smartling
|
6
|
+
# files, contexts, strings and authentication API
|
7
|
+
module Smartling
|
8
|
+
class << self
|
9
|
+
# Gets a new Client
|
10
|
+
def new(*args)
|
11
|
+
Client.new(*args)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/smartring.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
require 'hipsterhash'
|
5
|
+
require 'httmultiparty'
|
6
|
+
require 'smartling/client'
|
7
|
+
|
8
|
+
describe Smartling::Auth do
|
9
|
+
describe 'authenticate (first time)' do
|
10
|
+
it 'POSTs to the authentication endpoint', :vcr do
|
11
|
+
client = Smartling::Client.new
|
12
|
+
client.authenticate!
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'authenticate (twice)' do
|
17
|
+
it 'POSTs to the authentication endpoint', :vcr do
|
18
|
+
client = Smartling::Client.new
|
19
|
+
client.authenticate!
|
20
|
+
client.refresh_token!
|
21
|
+
client.authenticate!
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
require 'smartling/client'
|
5
|
+
|
6
|
+
describe Smartling::Client, :vcr do
|
7
|
+
let(:options) { {} }
|
8
|
+
let(:client) { Smartling::Client.new(options) }
|
9
|
+
|
10
|
+
it('knows context') { assert client.is_a?(Smartling::Contexts) }
|
11
|
+
it('knows about files') { assert client.is_a?(Smartling::Files) }
|
12
|
+
it('knows about strings') { assert client.is_a?(Smartling::Strings) }
|
13
|
+
it('knows how to authenticate') { assert client.is_a?(Smartling::Auth) }
|
14
|
+
|
15
|
+
it 'can be created with options' do
|
16
|
+
c = Smartling::Client.new(project_id: 3)
|
17
|
+
refute_nil c.user_id
|
18
|
+
refute_nil c.user_secret
|
19
|
+
assert_equal 3, c.project_id
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'is cool with bullshit' do
|
23
|
+
path = '/no/such/path'
|
24
|
+
assert_raises { Smartling::Client.new.get(path) }
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'explains when credentials are borked' do
|
28
|
+
path = '/auth-api/v2/authorize'
|
29
|
+
assert_raises do
|
30
|
+
Smartling::Client.new(user_id: 'no', user_secret: 'way').get(path)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
require 'smartling/contexts'
|
5
|
+
|
6
|
+
describe Smartling::Contexts do
|
7
|
+
let(:smartling) do
|
8
|
+
Class.new(Minitest::Mock) do
|
9
|
+
include Smartling::Contexts
|
10
|
+
end.new
|
11
|
+
end
|
12
|
+
|
13
|
+
after { smartling.verify }
|
14
|
+
|
15
|
+
describe 'contexts' do
|
16
|
+
it 'lists contexts the items of the smartling contexts result' do
|
17
|
+
smartling.expect(:get, nil) do |path, query:|
|
18
|
+
assert_equal path, '/context-api/v2/projects/1/contexts'
|
19
|
+
assert_equal 'n', query.fetch(:nameFilter)
|
20
|
+
assert_equal 1, query.fetch(:offset)
|
21
|
+
assert_equal 'HTML', query.fetch(:type)
|
22
|
+
end
|
23
|
+
smartling.contexts(project_id: 1, name_filter: 'n',
|
24
|
+
offset: 1, type: 'HTML')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'context' do
|
29
|
+
it 'gets the /context with the right param' do
|
30
|
+
smartling.expect(:get, nil) do |path|
|
31
|
+
assert_equal '/context-api/v2/projects/1/contexts/x', path
|
32
|
+
end
|
33
|
+
smartling.context(project_id: 1, context_uid: 'x')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'download_context' do
|
38
|
+
it 'gets the /context with the right param' do
|
39
|
+
smartling.expect(:get, nil) do |path|
|
40
|
+
assert_equal '/context-api/v2/projects/1/contexts/x/content', path
|
41
|
+
end
|
42
|
+
smartling.download_context(project_id: 1, context_uid: 'x')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'delete_context' do
|
47
|
+
it 'deletes the context at the right endpoing' do
|
48
|
+
smartling.expect(:delete, nil) do |path|
|
49
|
+
assert_equal '/context-api/v2/projects/1/contexts/x', path
|
50
|
+
end
|
51
|
+
smartling.delete_context(project_id: 1, context_uid: 'x')
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe 'upload_context' do
|
56
|
+
it 'posts the right body to the right endpoint' do
|
57
|
+
smartling.expect(:post, nil) do |path, body:|
|
58
|
+
assert_equal '/context-api/v2/projects/1/contexts', path
|
59
|
+
assert_equal 'n', body.fetch(:name)
|
60
|
+
assert_equal '<i>Hi</i>', body.fetch(:content).read
|
61
|
+
assert_equal 'text/html', body.fetch(:content).content_type
|
62
|
+
assert_equal 'n', body.fetch(:name)
|
63
|
+
end
|
64
|
+
content = UploadIO.new(StringIO.new('<i>Hi</i>'), 'text/html')
|
65
|
+
smartling.upload_context(project_id: 1, content: content, name: 'n')
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'prints a helpful message if the contextType is unsupported' do
|
69
|
+
assert_raises Smartling::Contexts::InvalidContent do
|
70
|
+
smartling.upload_context(project_id: 1, content: 'not a file')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe 'upload_context_and_match' do
|
76
|
+
it 'posts the right body to the right endpoint' do
|
77
|
+
smartling.expect(:post, nil) do |path, body:|
|
78
|
+
expected = '/context-api/v2/projects/1/contexts/'
|
79
|
+
expected += 'upload-and-match-async'
|
80
|
+
assert_equal expected, path
|
81
|
+
assert_equal 'n', body.fetch(:name)
|
82
|
+
assert_equal '<i>Hi</i>', body.fetch(:content).read
|
83
|
+
assert_equal 'text/html', body.fetch(:content).content_type
|
84
|
+
assert_equal %w[1 2 3], body.fetch(:matchParams)
|
85
|
+
assert_equal 'n', body.fetch(:name)
|
86
|
+
end
|
87
|
+
content = UploadIO.new(StringIO.new('<i>Hi</i>'), 'text/html')
|
88
|
+
smartling.upload_context_and_match(project_id: 1, content: content,
|
89
|
+
match_params: %w[1 2 3], name: 'n')
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'prints a helpful message if the contextType is unsupported' do
|
93
|
+
assert_raises Smartling::Contexts::InvalidContent do
|
94
|
+
smartling.upload_context(project_id: 1, content: 'not a file')
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe 'async context matching' do
|
100
|
+
it 'posts to the right endpoint with the right params' do
|
101
|
+
smartling.expect(:post, nil) do |path, query:, headers:|
|
102
|
+
assert_equal '/context-api/v2/projects/1/contexts/x/match/async', path
|
103
|
+
assert_equal %w[x], JSON.parse(query)['stringHashcodes']
|
104
|
+
assert_equal 'application/json', headers['Content-Type']
|
105
|
+
end
|
106
|
+
smartling.match_context(project_id: 1, context_uid: 'x',
|
107
|
+
hashcodes: %w[x])
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe 'retrieving match results' do
|
112
|
+
it 'get the right endpoint' do
|
113
|
+
smartling.expect(:get, nil) do |p|
|
114
|
+
assert_equal '/context-api/v2/projects/1/match/8', p
|
115
|
+
end
|
116
|
+
smartling.context_matches(project_id: 1, match_id: 8)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
require 'smartling/files'
|
5
|
+
|
6
|
+
describe Smartling::Files do
|
7
|
+
let(:smartling) do
|
8
|
+
Class.new(Minitest::Mock) do
|
9
|
+
include Smartling::Files
|
10
|
+
end.new
|
11
|
+
end
|
12
|
+
|
13
|
+
after { smartling.verify }
|
14
|
+
|
15
|
+
describe 'files' do
|
16
|
+
it 'lists files the items of the smartling files result' do
|
17
|
+
smartling.expect(:get, nil, ['/files-api/v2/projects/1/files/list'])
|
18
|
+
smartling.files(project_id: 1)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'file' do
|
23
|
+
it 'gets the /file/status endpoint with the right param' do
|
24
|
+
smartling.expect(:get, nil) do |path, query:|
|
25
|
+
assert_match %r{files-api/v2/projects/1/file/status$}, path
|
26
|
+
assert_equal({ fileUri: 'x' }, query)
|
27
|
+
end
|
28
|
+
smartling.file(project_id: 1, file_uri: 'x')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'file with locale' do
|
33
|
+
it 'gets the /locale/x/file/status endpoint with the right params' do
|
34
|
+
smartling.expect(:get, nil) do |path, query:|
|
35
|
+
assert_match %r{files-api/v2/projects/1/locales/es/file/status$}, path
|
36
|
+
assert_equal({ fileUri: 'x' }, query)
|
37
|
+
end
|
38
|
+
smartling.file(project_id: 1, file_uri: 'x', locale: 'es')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe 'delete_file' do
|
43
|
+
it 'posts the right body to the right endpoint' do
|
44
|
+
smartling.expect(:post, nil) do |path, body:|
|
45
|
+
assert_match %r{files-api/v2/projects/1/file/delete$}, path,
|
46
|
+
assert_equal({ fileUri: 'x' }, body)
|
47
|
+
end
|
48
|
+
smartling.delete_file(project_id: 1, file_uri: 'x')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe 'upload_file' do
|
53
|
+
it 'posts the right body to the right endpoint' do
|
54
|
+
smartling.expect(:post, nil) do |path, body:|
|
55
|
+
assert_equal '/files-api/v2/projects/1/file', path
|
56
|
+
assert_equal 'x', body.fetch(:fileUri)
|
57
|
+
assert_equal 'json', body.fetch(:fileType)
|
58
|
+
assert_equal '"hello"', body.fetch(:file).read
|
59
|
+
assert_equal 'application/json', body.fetch(:file).content_type
|
60
|
+
assert_equal 'cb', body.fetch(:callback)
|
61
|
+
assert_equal %w[a b], body.fetch(:localeIdsToAuthorize)
|
62
|
+
assert_equal 'bar', body.fetch('smartling.foo')
|
63
|
+
assert_equal false, body.fetch(:authorize)
|
64
|
+
end
|
65
|
+
file = UploadIO.new(StringIO.new('"hello"'), 'application/json')
|
66
|
+
smartling.upload_file(project_id: 1, file: file, file_uri: 'x',
|
67
|
+
file_type: 'json', callback: 'cb',
|
68
|
+
locales_to_authorize: %w[a b],
|
69
|
+
smartling: { foo: 'bar' }, authorize: false)
|
70
|
+
end
|
71
|
+
it 'throws an exception if the file is not a file' do
|
72
|
+
assert_raises Smartling::Files::InvalidFile do
|
73
|
+
smartling.upload_file(project_id: 1, file: 'hi', file_uri: 'x',
|
74
|
+
file_type: 'bullshit')
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
require 'smartling/strings'
|
5
|
+
|
6
|
+
describe Smartling::Strings do
|
7
|
+
let(:smartling) do
|
8
|
+
Class.new(Minitest::Mock) do
|
9
|
+
include Smartling::Strings
|
10
|
+
end.new
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'source_strings' do
|
14
|
+
it 'lists files the items of the smartling files result' do
|
15
|
+
smartling.expect(:get, nil) do |path, query:|
|
16
|
+
assert_equal path, '/strings-api/v2/projects/1/source-strings'
|
17
|
+
assert_equal 'x', query.fetch(:fileUri)
|
18
|
+
assert_equal ['a'], query.fetch(:stringHashcodes)
|
19
|
+
assert_equal 99, query.fetch(:limit)
|
20
|
+
assert_equal 2, query.fetch(:offset)
|
21
|
+
end
|
22
|
+
smartling.source_strings(project_id: 1, file_uri: 'x', hashcodes: ['a'],
|
23
|
+
limit: 99, offset: 2)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
require 'smartling'
|
5
|
+
|
6
|
+
describe Smartling do
|
7
|
+
it 'can be "instantiated"' do
|
8
|
+
assert_instance_of Smartling::Client, Smartling.new
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'handles things gracefully', :vcr do
|
12
|
+
client = Smartling::Client.new
|
13
|
+
assert_instance_of HipsterHash, client.files
|
14
|
+
assert_instance_of HipsterHash, client.translations(file_uri: 'boo')
|
15
|
+
end
|
16
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path('../lib', __dir__)
|
4
|
+
|
5
|
+
require 'simplecov'
|
6
|
+
SimpleCov.start
|
7
|
+
|
8
|
+
require 'minitest/autorun'
|
9
|
+
|
10
|
+
require 'dotenv'
|
11
|
+
Dotenv.load '.env.local', '.env.test'
|
12
|
+
|
13
|
+
require 'vcr'
|
14
|
+
require 'cgi'
|
15
|
+
VCR.configure do |vcr|
|
16
|
+
vcr.hook_into :webmock
|
17
|
+
vcr.cassette_library_dir = 'test/cassettes'
|
18
|
+
vcr.filter_sensitive_data('SMARTLING_PROJECT_ID') { ENV.fetch('SMARTLING_PROJECT_ID') }
|
19
|
+
vcr.filter_sensitive_data('SMARTLING_USER_ID') { ENV.fetch('SMARTLING_USER_ID') }
|
20
|
+
vcr.filter_sensitive_data('SMARTLING_USER_SECRET') { ENV.fetch('SMARTLING_USER_SECRET') }
|
21
|
+
end
|
22
|
+
|
23
|
+
require 'minitest-vcr'
|
24
|
+
MinitestVcr::Spec.configure!
|
25
|
+
|
26
|
+
require 'pry'
|