unobtainium 0.0.2 → 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/.codeclimate.yml +33 -0
- data/.rubocop.yml +3 -0
- data/.travis.yml +8 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +29 -1
- data/README.md +57 -0
- data/Rakefile +17 -0
- data/cuke/.gitignore +2 -0
- data/cuke/Gemfile +13 -0
- data/cuke/README.md +2 -0
- data/cuke/config/config.yml +6 -0
- data/cuke/features/step_definitions/steps.rb +12 -0
- data/cuke/features/support/env.rb +11 -0
- data/cuke/features/world.feature +4 -0
- data/lib/unobtainium.rb +3 -0
- data/lib/unobtainium/config.rb +29 -26
- data/lib/unobtainium/driver.rb +1 -1
- data/lib/unobtainium/runtime.rb +38 -12
- data/lib/unobtainium/version.rb +1 -1
- data/lib/unobtainium/world.rb +79 -0
- data/spec/config_spec.rb +82 -0
- data/spec/data/array.yaml +3 -0
- data/spec/data/arraymerge-local.yaml +2 -0
- data/spec/data/arraymerge.yaml +3 -0
- data/spec/data/empty.yml +1 -0
- data/spec/data/hash.yml +3 -0
- data/spec/data/hashmerge-local.yml +4 -0
- data/spec/data/hashmerge.yml +7 -0
- data/spec/data/mergefail-local.yaml +2 -0
- data/spec/data/mergefail.yaml +5 -0
- data/spec/data/test.json +4 -0
- data/spec/data/world.yml +5 -0
- data/spec/driver_spec.rb +65 -0
- data/spec/mock_driver.rb +27 -0
- data/spec/pathed_hash_spec.rb +63 -0
- data/spec/runtime_spec.rb +110 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/world_spec.rb +33 -0
- data/unobtainium.gemspec +4 -1
- metadata +93 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9464c7e860902fed8b6f41813261a19368aea2aa
|
4
|
+
data.tar.gz: f9498b642d79da6d09cbebd854bda897c6b737d1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 07d45f57984c9ffe4d7c12d8fa7a189a6e22e0638a4dab0bed898f423ba73a9ae0f484247d0c23824513bf93f3eedfc32b7e4212e6515d751611c2b1c34eaee7
|
7
|
+
data.tar.gz: c1378459dc8affa7f5d2a2ce96cfcf5d240b2bf45c83158be0a1d3bf81795ae5024821c99eb3cd3e00617e606cea21c6b43f7ea3eda29b70213a43c5a78f3d30
|
data/.codeclimate.yml
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
---
|
2
|
+
engines:
|
3
|
+
bundler-audit:
|
4
|
+
enabled: true
|
5
|
+
duplication:
|
6
|
+
enabled: true
|
7
|
+
exclude_fingerprints:
|
8
|
+
- d85d6f12c93d79ccd43868b8315d8816
|
9
|
+
- a8e2b4ccb258f16eda697c5f98e21823
|
10
|
+
- 442a316695836b4f4693fe3786cd3396
|
11
|
+
- 1c24bb5da72323796b645814cc006684
|
12
|
+
config:
|
13
|
+
languages:
|
14
|
+
- ruby
|
15
|
+
- javascript
|
16
|
+
- python
|
17
|
+
- php
|
18
|
+
fixme:
|
19
|
+
enabled: true
|
20
|
+
rubocop:
|
21
|
+
enabled: true
|
22
|
+
ratings:
|
23
|
+
paths:
|
24
|
+
- Gemfile.lock
|
25
|
+
- "**.inc"
|
26
|
+
- "**.js"
|
27
|
+
- "**.jsx"
|
28
|
+
- "**.module"
|
29
|
+
- "**.php"
|
30
|
+
- "**.py"
|
31
|
+
- "**.rb"
|
32
|
+
exclude_paths:
|
33
|
+
- spec/
|
data/.rubocop.yml
CHANGED
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,16 +1,35 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
unobtainium (0.0
|
4
|
+
unobtainium (0.1.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
9
|
ast (2.2.0)
|
10
|
+
codeclimate-test-reporter (0.5.0)
|
11
|
+
simplecov (>= 0.7.1, < 1.0.0)
|
12
|
+
diff-lcs (1.2.5)
|
13
|
+
docile (1.1.5)
|
14
|
+
json (1.8.3)
|
10
15
|
parser (2.3.0.7)
|
11
16
|
ast (~> 2.2)
|
12
17
|
powerpack (0.1.1)
|
13
18
|
rainbow (2.1.0)
|
19
|
+
rake (11.1.2)
|
20
|
+
rspec (3.4.0)
|
21
|
+
rspec-core (~> 3.4.0)
|
22
|
+
rspec-expectations (~> 3.4.0)
|
23
|
+
rspec-mocks (~> 3.4.0)
|
24
|
+
rspec-core (3.4.4)
|
25
|
+
rspec-support (~> 3.4.0)
|
26
|
+
rspec-expectations (3.4.0)
|
27
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
28
|
+
rspec-support (~> 3.4.0)
|
29
|
+
rspec-mocks (3.4.1)
|
30
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
31
|
+
rspec-support (~> 3.4.0)
|
32
|
+
rspec-support (3.4.1)
|
14
33
|
rubocop (0.39.0)
|
15
34
|
parser (>= 2.3.0.7, < 3.0)
|
16
35
|
powerpack (~> 0.1)
|
@@ -18,6 +37,11 @@ GEM
|
|
18
37
|
ruby-progressbar (~> 1.7)
|
19
38
|
unicode-display_width (~> 1.0, >= 1.0.1)
|
20
39
|
ruby-progressbar (1.7.5)
|
40
|
+
simplecov (0.11.2)
|
41
|
+
docile (~> 1.1.0)
|
42
|
+
json (~> 1.8)
|
43
|
+
simplecov-html (~> 0.10.0)
|
44
|
+
simplecov-html (0.10.0)
|
21
45
|
unicode-display_width (1.0.3)
|
22
46
|
|
23
47
|
PLATFORMS
|
@@ -25,7 +49,11 @@ PLATFORMS
|
|
25
49
|
|
26
50
|
DEPENDENCIES
|
27
51
|
bundler (~> 1.11)
|
52
|
+
codeclimate-test-reporter
|
53
|
+
rake (~> 11.1)
|
54
|
+
rspec (~> 3.4)
|
28
55
|
rubocop (~> 0.39)
|
56
|
+
simplecov (~> 0.11)
|
29
57
|
unobtainium!
|
30
58
|
|
31
59
|
BUNDLED WITH
|
data/README.md
CHANGED
@@ -13,6 +13,63 @@ Some additional useful functionality for the maintenance of test suites is
|
|
13
13
|
also added.
|
14
14
|
|
15
15
|
[![Gem Version](https://badge.fury.io/rb/unobtainium.svg)](https://badge.fury.io/rb/unobtainium)
|
16
|
+
[![Build status](https://travis-ci.org/jfinkhaeuser/unobtainium.svg?branch=master)](https://travis-ci.org/jfinkhaeuser/unobtainium)
|
17
|
+
[![Code Climate](https://codeclimate.com/github/jfinkhaeuser/unobtainium/badges/gpa.svg)](https://codeclimate.com/github/jfinkhaeuser/unobtainium)
|
18
|
+
[![Test Coverage](https://codeclimate.com/github/jfinkhaeuser/unobtainium/badges/coverage.svg)](https://codeclimate.com/github/jfinkhaeuser/unobtainium/coverage)
|
19
|
+
|
20
|
+
# Usage
|
21
|
+
|
22
|
+
You can use unobtainium on its own, or use it as part of a
|
23
|
+
[cucumber](https://cucumber.io/) test suite.
|
24
|
+
|
25
|
+
Unobtainium's functionality is in standalone classes, but it's all combined in
|
26
|
+
the `Unobtainium::World` module.
|
27
|
+
|
28
|
+
- The `PathedHash` class extends `Hash` by allowing paths to nested values, e.g.:
|
29
|
+
```ruby
|
30
|
+
h = PathedHash.new { "foo" => { "bar" => 42 }}
|
31
|
+
h["foo.bar"] == 42 # true
|
32
|
+
```
|
33
|
+
- The `Config` class is a `PathedHash`, but also reads JSON or YAML files to
|
34
|
+
initialize itself with values, and allows config paths to be overridden by
|
35
|
+
environment variables: `FOO_BAR` overrides the "foo.bar" path.
|
36
|
+
|
37
|
+
You can use JSON as environment variable values.
|
38
|
+
- The `Runtime` class is a singleton and a `Hash`-like container (but simpler),
|
39
|
+
that destroys all of its contents at the end of a script, calling custom
|
40
|
+
destructors if required. That allows for clean teardown and avoids everything
|
41
|
+
to have to implement the Singleton pattern itself.
|
42
|
+
- The `Driver` class, of course, wraps either of Appium or Selenium drivers:
|
43
|
+
```ruby
|
44
|
+
drv = Driver.create(:firefox) # uses Selenium
|
45
|
+
drv = Driver.create(:android) # uses Appium
|
46
|
+
|
47
|
+
drv.navigate.to "..." # delegates to Selenium or Appium
|
48
|
+
```
|
49
|
+
|
50
|
+
## World
|
51
|
+
|
52
|
+
The World module combines all of the above by providing a simple entry point
|
53
|
+
for everything:
|
54
|
+
|
55
|
+
- `World.config_file` can be set to the path of a config file to be loaded,
|
56
|
+
defaulting to `config/config.yml`.
|
57
|
+
- `World#config` is a `Config` instance containing the above file's contents.
|
58
|
+
- `World#driver` returns a Driver, initialized to the settings contained in
|
59
|
+
the configuration file.
|
60
|
+
|
61
|
+
For a simple usage example of the World module, see the [cuke](./cuke)
|
62
|
+
subdirectory (used with cucumber).
|
63
|
+
|
64
|
+
## Configuration File
|
65
|
+
|
66
|
+
The configuration file knows two configuration variables:
|
67
|
+
|
68
|
+
- `driver` is expected to be a string, specifying the driver to use as if it
|
69
|
+
was passed to `Driver.create` (see above), e.g. "android", "chrome", etc.
|
70
|
+
- `drivers` (note the trailing s) is a Hash. Under each key you can nest an
|
71
|
+
options hash you might otherwise pass to `Driver.create` as the second
|
72
|
+
parameter.
|
16
73
|
|
17
74
|
# Credits
|
18
75
|
This gem is inspired by [LapisLazuli](https://github.com/spriteCloud/lapis-lazuli),
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# Rubocop
|
2
|
+
require 'rubocop/rake_task'
|
3
|
+
RuboCop::RakeTask.new
|
4
|
+
|
5
|
+
# Rspec
|
6
|
+
require 'rspec/core/rake_task'
|
7
|
+
RSpec::Core::RakeTask.new(:spec)
|
8
|
+
|
9
|
+
# Combined test task
|
10
|
+
desc "Test the code"
|
11
|
+
task :test do
|
12
|
+
Rake::Task[:rubocop].invoke
|
13
|
+
Rake::Task[:spec].invoke
|
14
|
+
end
|
15
|
+
|
16
|
+
# Default is the test task
|
17
|
+
task default: :test
|
data/cuke/.gitignore
ADDED
data/cuke/Gemfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
source 'http://rubygems.org'
|
2
|
+
|
3
|
+
# Cucumber
|
4
|
+
gem 'cucumber'
|
5
|
+
|
6
|
+
# For drivers
|
7
|
+
gem 'appium_lib'
|
8
|
+
gem 'selenium-webdriver'
|
9
|
+
|
10
|
+
# unobtainium itself; test code should point to the current repo and branch
|
11
|
+
repo = `git config --get remote.origin.url`.strip
|
12
|
+
branch = `git rev-parse --abbrev-ref HEAD`.strip
|
13
|
+
gem 'unobtainium', git: repo, branch: branch
|
data/cuke/README.md
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
#
|
3
|
+
# unobtainium
|
4
|
+
# https://github.com/jfinkhaeuser/unobtainium
|
5
|
+
#
|
6
|
+
# Copyright (c) 2016 Jens Finkhaeuser and other unobtainium contributors.
|
7
|
+
# All rights reserved.
|
8
|
+
#
|
9
|
+
|
10
|
+
Given(/^I navigate to the best website in the world$/) do
|
11
|
+
driver.navigate.to "http://finkhaeuser.de"
|
12
|
+
end
|
data/lib/unobtainium.rb
CHANGED
data/lib/unobtainium/config.rb
CHANGED
@@ -14,9 +14,9 @@ require 'unobtainium/pathed_hash'
|
|
14
14
|
module Unobtainium
|
15
15
|
##
|
16
16
|
# The Config class extends PathedHash by two main pieces of functionality:
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
17
|
+
# - it loads configuration files and turns them into pathed hashes, and
|
18
|
+
# - it treats environment variables as overriding anything contained in
|
19
|
+
# the configuration file.
|
20
20
|
#
|
21
21
|
# For configuration file loading, a named configuration file will be laoaded
|
22
22
|
# if present. A file with the same name but '-local' appended before the
|
@@ -34,7 +34,8 @@ module Unobtainium
|
|
34
34
|
#
|
35
35
|
# Note: if your configuration file's top-level structure is an array, it will
|
36
36
|
# be returned as a hash with a 'config' key that maps to your file's contents.
|
37
|
-
#
|
37
|
+
# That means that if you are trying to merge a hash with an array config, the
|
38
|
+
# result may be unexpected.
|
38
39
|
class Config < PathedHash
|
39
40
|
# Very simple YAML parser
|
40
41
|
class YAMLParser
|
@@ -97,29 +98,22 @@ module Unobtainium
|
|
97
98
|
# Load base and local configuration files
|
98
99
|
base, config = load_base_config(path)
|
99
100
|
_, local_config = load_local_config(base)
|
100
|
-
|
101
|
-
|
102
|
-
# don't match.
|
103
|
-
if config.class != local_config.class
|
104
|
-
raise ArgumentError, "Config file and local override file do not have "\
|
105
|
-
"the same top-level structure (hash or array), and therefore "\
|
106
|
-
"cannot be merged!"
|
101
|
+
if local_config.nil?
|
102
|
+
return Config.new(config)
|
107
103
|
end
|
108
104
|
|
109
105
|
# Merge
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
106
|
+
merger = proc do |_, v1, v2|
|
107
|
+
# rubocop:disable Style/GuardClause
|
108
|
+
if v1.is_a? Hash and v2.is_a? Hash
|
109
|
+
next v1.merge(v2, &merger)
|
110
|
+
elsif v1.is_a? Array and v2.is_a? Array
|
111
|
+
next v1 + v2
|
116
112
|
end
|
117
|
-
|
118
|
-
|
119
|
-
else
|
120
|
-
raise "Unexpected top-level structure in configuration file: "\
|
121
|
-
"#{config.class}"
|
113
|
+
next v2
|
114
|
+
# rubocop:enable Style/GuardClause
|
122
115
|
end
|
116
|
+
config.merge!(local_config, &merger)
|
123
117
|
|
124
118
|
return Config.new(config)
|
125
119
|
end
|
@@ -143,7 +137,7 @@ module Unobtainium
|
|
143
137
|
# Parse the contents.
|
144
138
|
config = FILE_TO_PARSER[base.extname].parse(contents)
|
145
139
|
|
146
|
-
return base, config
|
140
|
+
return base, hashify(config)
|
147
141
|
end
|
148
142
|
|
149
143
|
def load_local_config(base)
|
@@ -151,9 +145,8 @@ module Unobtainium
|
|
151
145
|
local = Pathname.new(base.dirname)
|
152
146
|
local = local.join(base.basename(base.extname).to_s + "-local" +
|
153
147
|
base.extname)
|
154
|
-
puts local
|
155
148
|
if not local.exist?
|
156
|
-
return
|
149
|
+
return local, nil
|
157
150
|
end
|
158
151
|
|
159
152
|
# We know the local override file exists, but we do want to let any errors
|
@@ -163,7 +156,17 @@ module Unobtainium
|
|
163
156
|
|
164
157
|
local_config = FILE_TO_PARSER[base.extname].parse(contents)
|
165
158
|
|
166
|
-
return local, local_config
|
159
|
+
return local, hashify(local_config)
|
160
|
+
end
|
161
|
+
|
162
|
+
def hashify(data)
|
163
|
+
if data.nil?
|
164
|
+
return {}
|
165
|
+
end
|
166
|
+
if data.is_a? Array
|
167
|
+
data = { ARRAY_KEY => data }
|
168
|
+
end
|
169
|
+
return data
|
167
170
|
end
|
168
171
|
end # class << self
|
169
172
|
end # class Config
|
data/lib/unobtainium/driver.rb
CHANGED
data/lib/unobtainium/runtime.rb
CHANGED
@@ -28,7 +28,7 @@ module Unobtainium
|
|
28
28
|
# Create our own finalizer
|
29
29
|
ObjectSpace.define_finalizer(self) do
|
30
30
|
@objects.keys.each do |key|
|
31
|
-
|
31
|
+
delete(key)
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
@@ -53,8 +53,8 @@ module Unobtainium
|
|
53
53
|
# If a destructor is passed, it is used to destroy the *new* object only.
|
54
54
|
# If no destructor is passed and the object responds to a :destroy method, that
|
55
55
|
# method is called.
|
56
|
-
def
|
57
|
-
|
56
|
+
def store(name, object, destructor = nil)
|
57
|
+
delete(name)
|
58
58
|
|
59
59
|
@objects[name] = [object, destructor]
|
60
60
|
|
@@ -65,8 +65,8 @@ module Unobtainium
|
|
65
65
|
# Store the object returned by the block, if any. If no object is returned
|
66
66
|
# or no block is given, this function does nothing.
|
67
67
|
#
|
68
|
-
# Otherwise it works much like :
|
69
|
-
def
|
68
|
+
# Otherwise it works much like :store above.
|
69
|
+
def store_with(name, destructor = nil, &block)
|
70
70
|
object = nil
|
71
71
|
if not block.nil?
|
72
72
|
object = yield
|
@@ -76,12 +76,30 @@ module Unobtainium
|
|
76
76
|
return
|
77
77
|
end
|
78
78
|
|
79
|
-
return
|
79
|
+
return store(name, object, destructor)
|
80
80
|
end
|
81
81
|
|
82
82
|
##
|
83
|
-
#
|
84
|
-
def
|
83
|
+
# Like :store, but only stores the object if none exists for that key yet.
|
84
|
+
def store_if(name, object, destructor = nil)
|
85
|
+
if has?(name)
|
86
|
+
return self[name]
|
87
|
+
end
|
88
|
+
return store(name, object, destructor)
|
89
|
+
end
|
90
|
+
|
91
|
+
##
|
92
|
+
# Like :store_if, but as a block version similar to :store_with.
|
93
|
+
def store_with_if(name, destructor = nil, &block)
|
94
|
+
if has?(name)
|
95
|
+
return self[name]
|
96
|
+
end
|
97
|
+
return store_with(name, destructor, &block)
|
98
|
+
end
|
99
|
+
|
100
|
+
##
|
101
|
+
# Deletes (and destroys) any object found under the given name.
|
102
|
+
def delete(name)
|
85
103
|
if not @objects.key?(name)
|
86
104
|
return
|
87
105
|
end
|
@@ -95,14 +113,23 @@ module Unobtainium
|
|
95
113
|
# Returns the object with the given name, or the default value if no such
|
96
114
|
# object exists.
|
97
115
|
def fetch(name, default = nil)
|
98
|
-
return @objects.fetch(name
|
116
|
+
return @objects.fetch(name)[0]
|
117
|
+
rescue KeyError
|
118
|
+
if default.nil?
|
119
|
+
raise
|
120
|
+
end
|
121
|
+
return default
|
99
122
|
end
|
100
123
|
|
101
124
|
##
|
102
125
|
# Similar to :fetch, but always returns nil for an object that could not
|
103
126
|
# be found.
|
104
127
|
def [](name)
|
105
|
-
|
128
|
+
val = @objects[name]
|
129
|
+
if val.nil?
|
130
|
+
return nil
|
131
|
+
end
|
132
|
+
return val[0]
|
106
133
|
end
|
107
134
|
|
108
135
|
private
|
@@ -111,8 +138,7 @@ module Unobtainium
|
|
111
138
|
# Destroy the given object with the destructor provided.
|
112
139
|
def destroy(object, destructor)
|
113
140
|
if not destructor.nil?
|
114
|
-
destructor.call
|
115
|
-
return
|
141
|
+
return destructor.call(object)
|
116
142
|
end
|
117
143
|
|
118
144
|
if not object.respond_to?(:destroy)
|
data/lib/unobtainium/version.rb
CHANGED
@@ -0,0 +1,79 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
#
|
3
|
+
# unobtainium
|
4
|
+
# https://github.com/jfinkhaeuser/unobtainium
|
5
|
+
#
|
6
|
+
# Copyright (c) 2016 Jens Finkhaeuser and other unobtainium contributors.
|
7
|
+
# All rights reserved.
|
8
|
+
#
|
9
|
+
require 'unobtainium'
|
10
|
+
|
11
|
+
require 'unobtainium/driver'
|
12
|
+
require 'unobtainium/config'
|
13
|
+
require 'unobtainium/runtime'
|
14
|
+
|
15
|
+
module Unobtainium
|
16
|
+
##
|
17
|
+
# The World module combines other modules, defining simpler entry points
|
18
|
+
# into the gem's functionality.
|
19
|
+
module World
|
20
|
+
##
|
21
|
+
# Modules can have class methods, too.
|
22
|
+
module ClassMethods
|
23
|
+
# Configuration related
|
24
|
+
def config_file=(name)
|
25
|
+
@config_file = name
|
26
|
+
end
|
27
|
+
|
28
|
+
def config_file
|
29
|
+
return @config_file || "config/config.yml"
|
30
|
+
end
|
31
|
+
end # module ClassMethods
|
32
|
+
extend ClassMethods
|
33
|
+
|
34
|
+
##
|
35
|
+
# Return the global configuration, loaded from :config_file
|
36
|
+
def config
|
37
|
+
return ::Unobtainium::Runtime.instance.store_with_if(:config) do
|
38
|
+
::Unobtainium::Config.load_config(::Unobtainium::World.config_file)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# Returns a driver instance with the given options. If no options are
|
44
|
+
# provided, options from the global configuration are used.
|
45
|
+
def driver(label = nil, options = nil)
|
46
|
+
# Make sure we have a label for the driver
|
47
|
+
if label.nil?
|
48
|
+
label = config["driver"]
|
49
|
+
end
|
50
|
+
|
51
|
+
# Make sure we have options matching the driver
|
52
|
+
if options.nil?
|
53
|
+
options = config["drivers.#{label}"]
|
54
|
+
end
|
55
|
+
|
56
|
+
# Create a key for the label and options. This should always
|
57
|
+
# return the same key for the same label and options.
|
58
|
+
key = { label: label, options: options }
|
59
|
+
require 'digest/sha1'
|
60
|
+
key = Digest::SHA1.hexdigest(key.to_s)
|
61
|
+
key = "driver-#{key}"
|
62
|
+
|
63
|
+
# Only create a driver with this exact configuration once
|
64
|
+
dtor = ::Unobtainium::World.method(:driver_destructor)
|
65
|
+
return ::Unobtainium::Runtime.instance.store_with_if(key, dtor) do
|
66
|
+
::Unobtainium::Driver.create(label, options)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class << self
|
71
|
+
def driver_destructor(the_driver = nil)
|
72
|
+
if the_driver.nil?
|
73
|
+
return
|
74
|
+
end
|
75
|
+
the_driver.close
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end # module World
|
79
|
+
end # module Unobtainium
|
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require_relative '../lib/unobtainium/config'
|
3
|
+
|
4
|
+
describe ::Unobtainium::Config do
|
5
|
+
before :each do
|
6
|
+
@data_path = File.join(File.dirname(__FILE__), 'data')
|
7
|
+
end
|
8
|
+
|
9
|
+
it "fails to load a nonexistent file" do
|
10
|
+
expect { ::Unobtainium::Config.load_config("_nope_.yaml") }.to \
|
11
|
+
raise_error Errno::ENOENT
|
12
|
+
end
|
13
|
+
|
14
|
+
it "is asked to load an unrecognized extension" do
|
15
|
+
expect { ::Unobtainium::Config.load_config("_nope_.cfg") }.to \
|
16
|
+
raise_error ArgumentError
|
17
|
+
end
|
18
|
+
|
19
|
+
it "loads a yaml config with a top-level hash correctly" do
|
20
|
+
config = File.join(@data_path, 'hash.yml')
|
21
|
+
cfg = ::Unobtainium::Config.load_config(config)
|
22
|
+
|
23
|
+
expect(cfg["foo"]).to eql "bar"
|
24
|
+
expect(cfg["baz"]).to eql "quux"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "loads a yaml config with a top-level array correctly" do
|
28
|
+
config = File.join(@data_path, 'array.yaml')
|
29
|
+
cfg = ::Unobtainium::Config.load_config(config)
|
30
|
+
|
31
|
+
expect(cfg["config"]).to eql %w(foo bar)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "loads a JSON config correctly" do
|
35
|
+
config = File.join(@data_path, 'test.json')
|
36
|
+
cfg = ::Unobtainium::Config.load_config(config)
|
37
|
+
|
38
|
+
expect(cfg["foo"]).to eql "bar"
|
39
|
+
expect(cfg["baz"]).to eql 42
|
40
|
+
end
|
41
|
+
|
42
|
+
it "merges a hashed config correctly" do
|
43
|
+
config = File.join(@data_path, 'hashmerge.yml')
|
44
|
+
cfg = ::Unobtainium::Config.load_config(config)
|
45
|
+
|
46
|
+
expect(cfg["asdf"]).to eql 1
|
47
|
+
expect(cfg["foo.bar"]).to eql "baz"
|
48
|
+
expect(cfg["foo.quux"]).to eql [1, 42]
|
49
|
+
expect(cfg["foo.baz"]).to eql 3.14
|
50
|
+
expect(cfg["blargh"]).to eql false
|
51
|
+
end
|
52
|
+
|
53
|
+
it "merges an array config correctly" do
|
54
|
+
config = File.join(@data_path, 'arraymerge.yaml')
|
55
|
+
cfg = ::Unobtainium::Config.load_config(config)
|
56
|
+
|
57
|
+
expect(cfg["config"]).to eql %w(foo bar baz)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "merges an array and hash config" do
|
61
|
+
config = File.join(@data_path, 'mergefail.yaml')
|
62
|
+
cfg = ::Unobtainium::Config.load_config(config)
|
63
|
+
|
64
|
+
expect(cfg["config"]).to eql %w(array in main config)
|
65
|
+
expect(cfg["local"]).to eql "override is a hash"
|
66
|
+
end
|
67
|
+
|
68
|
+
it "overrides configuration variables from the environment" do
|
69
|
+
config = File.join(@data_path, 'hash.yml')
|
70
|
+
cfg = ::Unobtainium::Config.load_config(config)
|
71
|
+
|
72
|
+
ENV["BAZ"] = "override"
|
73
|
+
expect(cfg["foo"]).to eql "bar"
|
74
|
+
expect(cfg["baz"]).to eql "override"
|
75
|
+
end
|
76
|
+
|
77
|
+
it "treats an empty YAML file as an empty hash" do
|
78
|
+
config = File.join(@data_path, 'empty.yml')
|
79
|
+
cfg = ::Unobtainium::Config.load_config(config)
|
80
|
+
expect(cfg).to be_empty
|
81
|
+
end
|
82
|
+
end
|
data/spec/data/empty.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
---
|
data/spec/data/hash.yml
ADDED
data/spec/data/test.json
ADDED
data/spec/data/world.yml
ADDED
data/spec/driver_spec.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require_relative '../lib/unobtainium/driver'
|
3
|
+
require_relative './mock_driver.rb'
|
4
|
+
|
5
|
+
class FakeDriver
|
6
|
+
end # class FakeDriver
|
7
|
+
|
8
|
+
describe ::Unobtainium::Driver do
|
9
|
+
before :each do
|
10
|
+
::Unobtainium::Driver.register_implementation(MockDriver, "mock_driver.rb")
|
11
|
+
end
|
12
|
+
|
13
|
+
it "refuses to register a driver with missing methods" do
|
14
|
+
expect do
|
15
|
+
::Unobtainium::Driver.register_implementation(FakeDriver, __FILE__)
|
16
|
+
end.to raise_error(LoadError)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "refuses to register the same driver twice from different locations" do
|
20
|
+
expect do
|
21
|
+
::Unobtainium::Driver.register_implementation(MockDriver, __FILE__)
|
22
|
+
end.to raise_error(LoadError)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "verifies arguments" do
|
26
|
+
expect { ::Unobtainium::Driver.create }.to raise_error(ArgumentError)
|
27
|
+
|
28
|
+
expect do
|
29
|
+
::Unobtainium::Driver.create(:mock, 1)
|
30
|
+
end.to raise_error(ArgumentError)
|
31
|
+
|
32
|
+
expect do
|
33
|
+
::Unobtainium::Driver.create(:mock, [])
|
34
|
+
end.to raise_error(ArgumentError)
|
35
|
+
|
36
|
+
expect do
|
37
|
+
::Unobtainium::Driver.create(:mock, "foo")
|
38
|
+
end.to raise_error(ArgumentError)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "creates no driver with an unknown label" do
|
42
|
+
expect { ::Unobtainium::Driver.create(:nope) }.to raise_error(LoadError)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "fails preconditions correctly" do
|
46
|
+
expect do
|
47
|
+
::Unobtainium::Driver.create(:raise_mock)
|
48
|
+
end.to raise_error(RuntimeError)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "creates a driver correctly" do
|
52
|
+
::Unobtainium::Driver.create(:mock)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "delegates to created driver class" do
|
56
|
+
drv = ::Unobtainium::Driver.create(:mock, foo: 42)
|
57
|
+
expect(drv.respond_to?(:passed_options)).to be_truthy
|
58
|
+
_ = drv.passed_options
|
59
|
+
end
|
60
|
+
|
61
|
+
it "passes options through correctly" do
|
62
|
+
drv = ::Unobtainium::Driver.create(:mock, foo: 42)
|
63
|
+
expect(drv.passed_options).to eql foo: 42
|
64
|
+
end
|
65
|
+
end
|
data/spec/mock_driver.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
class Mock
|
2
|
+
attr_accessor :passed_options
|
3
|
+
|
4
|
+
def initialize(opts)
|
5
|
+
@passed_options = opts
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
# rubocop:disable Style/GuardClause
|
10
|
+
class MockDriver
|
11
|
+
class << self
|
12
|
+
def matches?(label)
|
13
|
+
label == :mock || label == :raise_mock
|
14
|
+
end
|
15
|
+
|
16
|
+
def ensure_preconditions(label, _)
|
17
|
+
if label == :raise_mock
|
18
|
+
raise "something"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def create(_, options)
|
23
|
+
Mock.new(options)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end # class MockDriver
|
27
|
+
# rubocop:enable Style/GuardClause
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require_relative '../lib/unobtainium/pathed_hash'
|
3
|
+
|
4
|
+
describe ::Unobtainium::PathedHash do
|
5
|
+
describe "#initialize" do
|
6
|
+
it "can be constructed without values" do
|
7
|
+
ph = ::Unobtainium::PathedHash.new
|
8
|
+
expect(ph.empty?).to eql true
|
9
|
+
end
|
10
|
+
|
11
|
+
it "can be constructed with values" do
|
12
|
+
ph = ::Unobtainium::PathedHash.new(foo: 42)
|
13
|
+
expect(ph.empty?).to eql false
|
14
|
+
expect(ph[:foo]).to eql 42
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "Hash-like" do
|
19
|
+
it "responds to Hash functions" do
|
20
|
+
ph = ::Unobtainium::PathedHash.new
|
21
|
+
[:invert, :delete, :fetch].each do |meth|
|
22
|
+
expect(ph.respond_to?(meth)).to eql true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it "can be used like a hash" do
|
27
|
+
ph = ::Unobtainium::PathedHash.new(foo: 42)
|
28
|
+
inverted = ph.invert
|
29
|
+
expect(inverted.empty?).to eql false
|
30
|
+
expect(inverted[42]).to eql :foo
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it "can recursively read entries via a path" do
|
35
|
+
sample = {
|
36
|
+
"foo" => 42,
|
37
|
+
"bar" => {
|
38
|
+
"baz" => "quux",
|
39
|
+
"blah" => [1, 2],
|
40
|
+
}
|
41
|
+
}
|
42
|
+
ph = ::Unobtainium::PathedHash.new(sample)
|
43
|
+
|
44
|
+
expect(ph["foo"]).to eql 42
|
45
|
+
expect(ph["bar.baz"]).to eql "quux"
|
46
|
+
expect(ph["bar.blah"]).to eql [1, 2]
|
47
|
+
|
48
|
+
expect(ph["nope"]).to eql nil
|
49
|
+
expect(ph["bar.nope"]).to eql nil
|
50
|
+
end
|
51
|
+
|
52
|
+
it "can recursively write entries via a path" do
|
53
|
+
ph = ::Unobtainium::PathedHash.new
|
54
|
+
ph["foo.bar"] = 42
|
55
|
+
expect(ph["foo.bar"]).to eql 42
|
56
|
+
end
|
57
|
+
|
58
|
+
it "has the same string representation as the hash it's initialized from" do
|
59
|
+
h = { foo: 42 }
|
60
|
+
ph = ::Unobtainium::PathedHash.new(h)
|
61
|
+
expect(ph.to_s).to eql h.to_s
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require_relative '../lib/unobtainium/runtime'
|
3
|
+
|
4
|
+
# rubocop:disable Style/ClassVars
|
5
|
+
class Foo
|
6
|
+
@@instances = 0
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def instances
|
10
|
+
@@instances ||= 0
|
11
|
+
end
|
12
|
+
|
13
|
+
def instances=(value)
|
14
|
+
@@instances = value
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
Foo.instances += 1
|
20
|
+
end
|
21
|
+
|
22
|
+
def destroy
|
23
|
+
Foo.instances -= 1
|
24
|
+
end
|
25
|
+
end # class Foo
|
26
|
+
# rubocop:enable Style/ClassVars
|
27
|
+
|
28
|
+
describe ::Unobtainium::Runtime do
|
29
|
+
it "is a singleton" do
|
30
|
+
expect { ::Unobtainium::Runtime.new }.to raise_error(NoMethodError)
|
31
|
+
first = ::Unobtainium::Runtime.instance
|
32
|
+
second = ::Unobtainium::Runtime.instance
|
33
|
+
expect(first).to eql second
|
34
|
+
end
|
35
|
+
|
36
|
+
it "can store objects" do
|
37
|
+
::Unobtainium::Runtime.instance.store("foo", 42)
|
38
|
+
|
39
|
+
expect(::Unobtainium::Runtime.instance.has?("foo")).to be_truthy
|
40
|
+
expect(::Unobtainium::Runtime.instance.length).to eql 1
|
41
|
+
expect(::Unobtainium::Runtime.instance.fetch("foo")).to eql 42
|
42
|
+
expect(::Unobtainium::Runtime.instance["foo"]).to eql 42
|
43
|
+
end
|
44
|
+
|
45
|
+
it "deals well with default values" do
|
46
|
+
expect(::Unobtainium::Runtime.instance["bar"]).to be_nil
|
47
|
+
expect { ::Unobtainium::Runtime.instance.fetch("bar") }.to raise_error(
|
48
|
+
KeyError)
|
49
|
+
expect(::Unobtainium::Runtime.instance.fetch("bar", 123)).to eql 123
|
50
|
+
end
|
51
|
+
|
52
|
+
it "destroys deleted objects" do
|
53
|
+
expect(Foo.instances).to eql 0
|
54
|
+
|
55
|
+
::Unobtainium::Runtime.instance.store("foo", Foo.new)
|
56
|
+
expect(Foo.instances).to eql 1
|
57
|
+
|
58
|
+
::Unobtainium::Runtime.instance.delete("foo")
|
59
|
+
expect(Foo.instances).to eql 0
|
60
|
+
end
|
61
|
+
|
62
|
+
it "can use custom destructors" do
|
63
|
+
called = false
|
64
|
+
::Unobtainium::Runtime.instance.store("foo", 666, proc { called = true })
|
65
|
+
expect(called).to be_falsy
|
66
|
+
|
67
|
+
::Unobtainium::Runtime.instance.delete("foo")
|
68
|
+
expect(called).to be_truthy
|
69
|
+
end
|
70
|
+
|
71
|
+
it "can store objects created from a block" do
|
72
|
+
::Unobtainium::Runtime.instance.store_with("foo") { 123 }
|
73
|
+
expect(::Unobtainium::Runtime.instance.fetch("foo")).to eql 123
|
74
|
+
end
|
75
|
+
|
76
|
+
it "ignores nil objects created from a block" do
|
77
|
+
::Unobtainium::Runtime.instance.store_with("_nope_") { nil }
|
78
|
+
expect { ::Unobtainium::Runtime.instance.fetch("_nope_") }.to raise_error(
|
79
|
+
KeyError)
|
80
|
+
end
|
81
|
+
|
82
|
+
it "stores objects with :store_if" do
|
83
|
+
::Unobtainium::Runtime.instance.store_if("store_if", 42)
|
84
|
+
expect(::Unobtainium::Runtime.instance.fetch("store_if")).to eql 42
|
85
|
+
end
|
86
|
+
|
87
|
+
it "does not overwrite objects with :store_if" do
|
88
|
+
::Unobtainium::Runtime.instance.store("foo", 42)
|
89
|
+
::Unobtainium::Runtime.instance.store_if("foo", 123)
|
90
|
+
expect(::Unobtainium::Runtime.instance.fetch("foo")).to eql 42
|
91
|
+
end
|
92
|
+
|
93
|
+
it "stores objects with :store_with_if" do
|
94
|
+
::Unobtainium::Runtime.instance.store_with_if("store_with_if") do
|
95
|
+
42
|
96
|
+
end
|
97
|
+
expect(::Unobtainium::Runtime.instance.fetch("store_with_if")).to eql 42
|
98
|
+
end
|
99
|
+
|
100
|
+
it "does not overwrite objects with :store_with_if" do
|
101
|
+
::Unobtainium::Runtime.instance.store("foo", 42)
|
102
|
+
called = false
|
103
|
+
::Unobtainium::Runtime.instance.store_with_if("foo") do
|
104
|
+
called = true
|
105
|
+
123
|
106
|
+
end
|
107
|
+
expect(::Unobtainium::Runtime.instance.fetch("foo")).to eql 42
|
108
|
+
expect(called).to be_falsy
|
109
|
+
end
|
110
|
+
end
|
data/spec/spec_helper.rb
ADDED
data/spec/world_spec.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require_relative '../lib/unobtainium/world'
|
3
|
+
require_relative './mock_driver.rb'
|
4
|
+
|
5
|
+
class Tester
|
6
|
+
include ::Unobtainium::World
|
7
|
+
end # class Tester
|
8
|
+
|
9
|
+
describe ::Unobtainium::World do
|
10
|
+
before :each do
|
11
|
+
# Set configuration
|
12
|
+
path = File.join(File.dirname(__FILE__), 'data', 'world.yml')
|
13
|
+
::Unobtainium::World.config_file = path
|
14
|
+
|
15
|
+
# Load MockDriver
|
16
|
+
::Unobtainium::Driver.register_implementation(MockDriver, "mock_driver.rb")
|
17
|
+
|
18
|
+
# Create tester object
|
19
|
+
@tester = Tester.new
|
20
|
+
end
|
21
|
+
|
22
|
+
it "loads the global config" do
|
23
|
+
expect(@tester.config["drivers.mock.option"]).to eql "value"
|
24
|
+
end
|
25
|
+
|
26
|
+
it "creates a mock driver parameters" do
|
27
|
+
expect(@tester.driver.respond_to?(:passed_options)).to be_truthy
|
28
|
+
end
|
29
|
+
|
30
|
+
it "passed the config file options to the driver" do
|
31
|
+
expect(@tester.driver.passed_options["option"]).to eql "value"
|
32
|
+
end
|
33
|
+
end
|
data/unobtainium.gemspec
CHANGED
@@ -37,12 +37,15 @@ Gem::Specification.new do |spec|
|
|
37
37
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
38
38
|
spec.require_paths = ["lib"]
|
39
39
|
|
40
|
-
spec.required_ruby_version = '>=
|
40
|
+
spec.required_ruby_version = '>= 2.0'
|
41
41
|
|
42
42
|
spec.requirements = "Either or all of 'selenium-webdriver', 'appium_lib'"
|
43
43
|
|
44
44
|
spec.add_development_dependency "bundler", "~> 1.11"
|
45
45
|
spec.add_development_dependency "rubocop", "~> 0.39"
|
46
|
+
spec.add_development_dependency "rake", "~> 11.1"
|
47
|
+
spec.add_development_dependency "rspec", "~> 3.4"
|
48
|
+
spec.add_development_dependency "simplecov", "~> 0.11"
|
46
49
|
end
|
47
50
|
# rubocop:enable Style/SpaceAroundOperators
|
48
51
|
# rubocop:enable Style/UnneededPercentQ, Style/ExtraSpacing
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unobtainium
|
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
|
- Jens Finkhaeuser
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-04-
|
11
|
+
date: 2016-04-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -38,6 +38,48 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0.39'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '11.1'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '11.1'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.4'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.4'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: simplecov
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.11'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.11'
|
41
83
|
description: "\n Unobtainium wraps Selenium and Appium in a simple driver abstraction
|
42
84
|
so that\n test code can more easily cover desktop browsers, mobile browsers and
|
43
85
|
mobile\n apps.\n\n Some additional useful functionality for the maintenance
|
@@ -48,12 +90,22 @@ executables: []
|
|
48
90
|
extensions: []
|
49
91
|
extra_rdoc_files: []
|
50
92
|
files:
|
93
|
+
- ".codeclimate.yml"
|
51
94
|
- ".gitignore"
|
52
95
|
- ".rubocop.yml"
|
96
|
+
- ".travis.yml"
|
53
97
|
- Gemfile
|
54
98
|
- Gemfile.lock
|
55
99
|
- LICENSE
|
56
100
|
- README.md
|
101
|
+
- Rakefile
|
102
|
+
- cuke/.gitignore
|
103
|
+
- cuke/Gemfile
|
104
|
+
- cuke/README.md
|
105
|
+
- cuke/config/config.yml
|
106
|
+
- cuke/features/step_definitions/steps.rb
|
107
|
+
- cuke/features/support/env.rb
|
108
|
+
- cuke/features/world.feature
|
57
109
|
- lib/unobtainium.rb
|
58
110
|
- lib/unobtainium/config.rb
|
59
111
|
- lib/unobtainium/driver.rb
|
@@ -62,6 +114,25 @@ files:
|
|
62
114
|
- lib/unobtainium/pathed_hash.rb
|
63
115
|
- lib/unobtainium/runtime.rb
|
64
116
|
- lib/unobtainium/version.rb
|
117
|
+
- lib/unobtainium/world.rb
|
118
|
+
- spec/config_spec.rb
|
119
|
+
- spec/data/array.yaml
|
120
|
+
- spec/data/arraymerge-local.yaml
|
121
|
+
- spec/data/arraymerge.yaml
|
122
|
+
- spec/data/empty.yml
|
123
|
+
- spec/data/hash.yml
|
124
|
+
- spec/data/hashmerge-local.yml
|
125
|
+
- spec/data/hashmerge.yml
|
126
|
+
- spec/data/mergefail-local.yaml
|
127
|
+
- spec/data/mergefail.yaml
|
128
|
+
- spec/data/test.json
|
129
|
+
- spec/data/world.yml
|
130
|
+
- spec/driver_spec.rb
|
131
|
+
- spec/mock_driver.rb
|
132
|
+
- spec/pathed_hash_spec.rb
|
133
|
+
- spec/runtime_spec.rb
|
134
|
+
- spec/spec_helper.rb
|
135
|
+
- spec/world_spec.rb
|
65
136
|
- unobtainium.gemspec
|
66
137
|
homepage: https://github.com/jfinkhaeuser/unobtainium
|
67
138
|
licenses:
|
@@ -75,7 +146,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
75
146
|
requirements:
|
76
147
|
- - ">="
|
77
148
|
- !ruby/object:Gem::Version
|
78
|
-
version: '
|
149
|
+
version: '2.0'
|
79
150
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
151
|
requirements:
|
81
152
|
- - ">="
|
@@ -88,5 +159,23 @@ rubygems_version: 2.4.5.1
|
|
88
159
|
signing_key:
|
89
160
|
specification_version: 4
|
90
161
|
summary: 'Obtain the unobtainable: test code covering multiple platforms'
|
91
|
-
test_files:
|
162
|
+
test_files:
|
163
|
+
- spec/config_spec.rb
|
164
|
+
- spec/data/array.yaml
|
165
|
+
- spec/data/arraymerge-local.yaml
|
166
|
+
- spec/data/arraymerge.yaml
|
167
|
+
- spec/data/empty.yml
|
168
|
+
- spec/data/hash.yml
|
169
|
+
- spec/data/hashmerge-local.yml
|
170
|
+
- spec/data/hashmerge.yml
|
171
|
+
- spec/data/mergefail-local.yaml
|
172
|
+
- spec/data/mergefail.yaml
|
173
|
+
- spec/data/test.json
|
174
|
+
- spec/data/world.yml
|
175
|
+
- spec/driver_spec.rb
|
176
|
+
- spec/mock_driver.rb
|
177
|
+
- spec/pathed_hash_spec.rb
|
178
|
+
- spec/runtime_spec.rb
|
179
|
+
- spec/spec_helper.rb
|
180
|
+
- spec/world_spec.rb
|
92
181
|
has_rdoc:
|