Class: ExecutableMock

Inherits:
Object
  • Object
show all
Includes:
Registry
Defined in:
lib/executable_mock.rb,
lib/executable_mock/version.rb,
lib/executable_mock/registry.rb

Defined Under Namespace

Modules: Registry

Constant Summary collapse

TEMPLATE_PATH =
File.expand_path("executable_mock/template.rb.erb", __dir__)
TEMPLATE =
ERB.new(File.read(TEMPLATE_PATH))
Error =
Class.new(StandardError)
VERSION =
"1.1.0"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Registry

#deregister_self, included, #register_self

Constructor Details

#initialize(name, mappings, ruby_bin: RbConfig.ruby, directory: Dir.mktmpdir) ⇒ ExecutableMock

Returns a new instance of ExecutableMock.



28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/executable_mock.rb', line 28

def initialize(name, mappings, ruby_bin: RbConfig.ruby, directory: Dir.mktmpdir)
  @mappings = mappings
  @ruby_bin = ruby_bin
  @name = name
  @file_path = File.join(directory, name)
  @path_setup = %(PATH="#{directory}:$PATH")
  call_error_log_file = Tempfile.new
  call_error_log_file.close
  @call_error_log_file_path = call_error_log_file.path

  write_executable
  register_self
end

Instance Attribute Details

#file_pathObject (readonly)

Returns the value of attribute file_path.



12
13
14
# File 'lib/executable_mock.rb', line 12

def file_path
  @file_path
end

#path_setupObject (readonly)

Returns the value of attribute path_setup.



12
13
14
# File 'lib/executable_mock.rb', line 12

def path_setup
  @path_setup
end

Class Method Details

.finalize_allObject



23
24
25
# File 'lib/executable_mock.rb', line 23

def finalize_all
  registry.each(&:finalize)
end

.generate(name, mappings, ruby_bin: RbConfig.ruby, directory: Dir.mktmpdir) ⇒ Object



15
16
17
18
19
20
21
# File 'lib/executable_mock.rb', line 15

def generate(name, mappings, ruby_bin: RbConfig.ruby, directory: Dir.mktmpdir)
  instance = new(name, mappings, ruby_bin: ruby_bin, directory: directory)

  yield(instance).tap do |result|
    instance.finalize(result)
  end
end

Instance Method Details

#check_call_error_log_fileObject

Raises:



55
56
57
58
59
# File 'lib/executable_mock.rb', line 55

def check_call_error_log_file
  return unless File.size?(@call_error_log_file_path)

  raise(Error, File.read(@call_error_log_file_path))
end

#check_mismatched_argvs_calls(argvs_map) ⇒ Object

Raises:



70
71
72
73
74
75
76
77
78
79
# File 'lib/executable_mock.rb', line 70

def check_mismatched_argvs_calls(argvs_map)
  mismatched_argvs_calls = @mappings.select do |argv, outputs|
    outputs.is_a?(Array) && outputs.size != argvs_map[argv]
  end

  raise(Error, <<~MESSAGE) if mismatched_argvs_calls.any?
    The following argvs were not called the correct number of times:
    #{mismatched_argvs_calls.inspect}
  MESSAGE
end

#check_uncalled_argvs(argvs_map) ⇒ Object

Raises:



61
62
63
64
65
66
67
68
# File 'lib/executable_mock.rb', line 61

def check_uncalled_argvs(argvs_map)
  uncalled_argvs = argvs_map.select { |_, v| v.zero? }

  raise(Error, <<~MESSAGE) if uncalled_argvs.any?
    The following argvs were not called:
    #{uncalled_argvs.keys.join("\n")}
  MESSAGE
end

#counter_cache_pathObject



81
82
83
84
85
86
87
88
89
# File 'lib/executable_mock.rb', line 81

def counter_cache_path
  @counter_cache_path ||= begin
    data = Marshal.dump(@mappings.transform_values { 0 })
    Tempfile.new.tap do |file|
      file.write(data)
      file.close
    end.path
  end
end

#finalize(command_result = nil) ⇒ Object



42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/executable_mock.rb', line 42

def finalize(command_result = nil)
  called_argvs_map = Marshal.load(File.read(counter_cache_path)) # rubocop:disable Security/MarshalLoad
  check_call_error_log_file
  check_uncalled_argvs(called_argvs_map)
  check_mismatched_argvs_calls(called_argvs_map)
rescue Error
  puts command_result if command_result
  raise
ensure
  FileUtils.rm_f([@file_path, @call_error_log_file_path, counter_cache_path])
  deregister_self
end

#write_executableObject



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/executable_mock.rb', line 91

def write_executable
  bindings = {
    ruby_bin: @ruby_bin,
    mappings: @mappings,
    name: @name,
    call_error_log_file_path: @call_error_log_file_path,
    counter_cache_path: counter_cache_path
  }

  executable_contents = TEMPLATE.result_with_hash(bindings)

  File.open(@file_path, "w") do |file|
    file.write(executable_contents)
  end
  File.chmod(0o755, @file_path)
end