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 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,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+ require "tempfile"
5
+ require "erb"
6
+ require "set"
@@ -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,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ExecutableMock
4
+ VERSION = "1.0.0"
5
+ 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: []