unobtainium 0.0.2 → 0.1.0
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 +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
|
[](https://badge.fury.io/rb/unobtainium)
|
16
|
+
[](https://travis-ci.org/jfinkhaeuser/unobtainium)
|
17
|
+
[](https://codeclimate.com/github/jfinkhaeuser/unobtainium)
|
18
|
+
[](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:
|