executable_mock 1.0.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 +7 -0
- data/lib/executable_mock/registry.rb +23 -0
- data/lib/executable_mock/stdlib.rb +6 -0
- data/lib/executable_mock/template.rb.erb +34 -0
- data/lib/executable_mock/version.rb +5 -0
- data/lib/executable_mock.rb +106 -0
- metadata +51 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 89e54f80480d9ec55c308051dea7c922eedfc79d0a1e8f8a33e7437d72890a28
|
4
|
+
data.tar.gz: 841ee2e10667111ff0b8ef3e40506b4960e17f408f139805140181884c66eb92
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f2085220dcf0c2e981ec4be0e30d5777fab09cd80a65d462737ec153c4f0aa29d67ddbb6ad2229281ad50c0c75ac9b88f25f74affb3b65d11dfbcca358e0f5c6
|
7
|
+
data.tar.gz: d6b243b5cbc886e1badf5ba30d617e7c7d7ee335b9e1388ed7cf2a946bda4ac5b532360e13fe0d98217b71f1579d5d243a28e6bf3ff063dc6f7ba56dac673003
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ExecutableMock
|
4
|
+
module Registry
|
5
|
+
def self.included(klass)
|
6
|
+
klass.extend(ClassMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def registry
|
11
|
+
Thread.current[:executable_mocks] ||= Set.new
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def register_self
|
16
|
+
self.class.registry << self
|
17
|
+
end
|
18
|
+
|
19
|
+
def deregister_self
|
20
|
+
self.class.registry.delete(self)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#!<%= ruby_bin %>
|
2
|
+
|
3
|
+
# Mappings
|
4
|
+
|
5
|
+
mappings = <%= mappings %>
|
6
|
+
argv_key = ARGV.join(" ")
|
7
|
+
unless mappings.key?(argv_key)
|
8
|
+
File.open("<%= call_error_log_file_path %>", "w") do |file|
|
9
|
+
file.write("The executable `<%= name %>` does not support these args:\n#{argv_key}")
|
10
|
+
file.write("\n\nSupported:\n<%= mappings.keys.join("\n") %>")
|
11
|
+
end
|
12
|
+
puts "ExecutableMock: Unsupported arguments"
|
13
|
+
exit 1
|
14
|
+
end
|
15
|
+
|
16
|
+
# Counter cache handler
|
17
|
+
|
18
|
+
call_count = nil
|
19
|
+
File.open("<%= counter_cache_path %>", "a+") do |file|
|
20
|
+
file.rewind
|
21
|
+
counter_cache = Marshal.load(file.read)
|
22
|
+
call_count = counter_cache[argv_key]
|
23
|
+
counter_cache[argv_key] += 1
|
24
|
+
file.truncate(0)
|
25
|
+
file.write(Marshal.dump(counter_cache))
|
26
|
+
end
|
27
|
+
|
28
|
+
# Output
|
29
|
+
|
30
|
+
if mappings[argv_key].is_a?(Array)
|
31
|
+
print mappings[argv_key].fetch(call_count)
|
32
|
+
else
|
33
|
+
print mappings[argv_key]
|
34
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "executable_mock/stdlib"
|
4
|
+
require "executable_mock/registry"
|
5
|
+
|
6
|
+
class ExecutableMock
|
7
|
+
include Registry
|
8
|
+
TEMPLATE_PATH = File.expand_path("executable_mock/template.rb.erb", __dir__)
|
9
|
+
TEMPLATE = ERB.new(File.read(TEMPLATE_PATH))
|
10
|
+
Error = Class.new(StandardError)
|
11
|
+
|
12
|
+
attr_reader :file_path, :path_setup
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def generate(name, mappings, ruby_bin: RbConfig.ruby, directory: Dir.mktmpdir)
|
16
|
+
instance = new(name, mappings, ruby_bin: ruby_bin, directory: directory)
|
17
|
+
|
18
|
+
yield(instance).tap do |result|
|
19
|
+
instance.finalize(result)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def finalize_all
|
24
|
+
registry.each(&:finalize)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(name, mappings, ruby_bin: RbConfig.ruby, directory: Dir.mktmpdir)
|
29
|
+
@mappings = mappings
|
30
|
+
@ruby_bin = ruby_bin
|
31
|
+
@name = name
|
32
|
+
@file_path = File.join(directory, name)
|
33
|
+
@path_setup = %(PATH="#{directory}:$PATH")
|
34
|
+
@call_error_log_file_path = Tempfile.new.path
|
35
|
+
|
36
|
+
write_executable
|
37
|
+
register_self
|
38
|
+
end
|
39
|
+
|
40
|
+
def finalize(command_result = nil)
|
41
|
+
called_argvs_map = Marshal.load(File.read(counter_cache_path)) # rubocop:disable Security/MarshalLoad
|
42
|
+
check_call_error_log_file
|
43
|
+
check_uncalled_argvs(called_argvs_map)
|
44
|
+
check_mismatched_argvs_calls(called_argvs_map)
|
45
|
+
rescue Error
|
46
|
+
puts command_result if command_result
|
47
|
+
raise
|
48
|
+
ensure
|
49
|
+
FileUtils.rm_f([@file_path, @call_error_log_file_path, counter_cache_path])
|
50
|
+
deregister_self
|
51
|
+
end
|
52
|
+
|
53
|
+
def check_call_error_log_file
|
54
|
+
return unless File.size?(@call_error_log_file_path)
|
55
|
+
|
56
|
+
raise(Error, File.read(@call_error_log_file_path))
|
57
|
+
end
|
58
|
+
|
59
|
+
def check_uncalled_argvs(argvs_map)
|
60
|
+
uncalled_argvs = argvs_map.select { |_, v| v.zero? }
|
61
|
+
|
62
|
+
raise(Error, <<~MESSAGE) if uncalled_argvs.any?
|
63
|
+
The following argvs were not called:
|
64
|
+
#{uncalled_argvs.keys.join("\n")}
|
65
|
+
MESSAGE
|
66
|
+
end
|
67
|
+
|
68
|
+
def check_mismatched_argvs_calls(argvs_map)
|
69
|
+
mismatched_argvs_calls = @mappings.select do |argv, outputs|
|
70
|
+
outputs.is_a?(Array) && outputs.size != argvs_map[argv]
|
71
|
+
end
|
72
|
+
|
73
|
+
raise(Error, <<~MESSAGE) if mismatched_argvs_calls.any?
|
74
|
+
The following argvs were not called the correct number of times:
|
75
|
+
#{mismatched_argvs_calls.inspect}
|
76
|
+
MESSAGE
|
77
|
+
end
|
78
|
+
|
79
|
+
def counter_cache_path
|
80
|
+
@counter_cache_path ||= begin
|
81
|
+
Tempfile.new.path.tap do |file_path|
|
82
|
+
data = Marshal.dump(@mappings.transform_values { 0 })
|
83
|
+
File.open(file_path, "w") do |file|
|
84
|
+
file.write(data)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def write_executable
|
91
|
+
bindings = {
|
92
|
+
ruby_bin: @ruby_bin,
|
93
|
+
mappings: @mappings,
|
94
|
+
name: @name,
|
95
|
+
call_error_log_file_path: @call_error_log_file_path,
|
96
|
+
counter_cache_path: counter_cache_path
|
97
|
+
}
|
98
|
+
|
99
|
+
executable_contents = TEMPLATE.result_with_hash(bindings)
|
100
|
+
|
101
|
+
File.open(@file_path, "w") do |file|
|
102
|
+
file.write(executable_contents)
|
103
|
+
end
|
104
|
+
File.chmod(0o755, @file_path)
|
105
|
+
end
|
106
|
+
end
|
metadata
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: executable_mock
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Christophe Maximin
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-12-03 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: PLACEHOLDER
|
14
|
+
email:
|
15
|
+
- christophe.maximin@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/executable_mock.rb
|
21
|
+
- lib/executable_mock/registry.rb
|
22
|
+
- lib/executable_mock/stdlib.rb
|
23
|
+
- lib/executable_mock/template.rb.erb
|
24
|
+
- lib/executable_mock/version.rb
|
25
|
+
homepage: https://github.com/christophemaximin/executable_mock
|
26
|
+
licenses: []
|
27
|
+
metadata:
|
28
|
+
homepage_uri: https://github.com/christophemaximin/executable_mock
|
29
|
+
source_code_uri: https://github.com/christophemaximin/executable_mock
|
30
|
+
changelog_uri: https://github.com/christophemaximin/executable_mock/CHANGELOG.md
|
31
|
+
post_install_message:
|
32
|
+
rdoc_options: []
|
33
|
+
require_paths:
|
34
|
+
- lib
|
35
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '2.6'
|
40
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
requirements: []
|
46
|
+
rubyforge_project:
|
47
|
+
rubygems_version: 3.0.0.beta2
|
48
|
+
signing_key:
|
49
|
+
specification_version: 4
|
50
|
+
summary: PLACEHOLDER
|
51
|
+
test_files: []
|