detect invalid Pack/Unpack directives
This commit is contained in:
parent
36e0d8f915
commit
61f70e09f6
|
@ -22,6 +22,7 @@ require:
|
|||
- ./lib/rubocop/cop/lint/module_disclosure_date_present.rb
|
||||
- ./lib/rubocop/cop/lint/deprecated_gem_version.rb
|
||||
- ./lib/rubocop/cop/lint/module_enforce_notes.rb
|
||||
- ./lib/rubocop/cop/lint/detect_invalid_pack_directives.rb
|
||||
|
||||
Layout/SpaceBeforeBrackets:
|
||||
Description: >-
|
||||
|
@ -166,6 +167,9 @@ Layout/ModuleHashValuesOnSameLine:
|
|||
Layout/ModuleDescriptionIndentation:
|
||||
Enabled: true
|
||||
|
||||
Lint/DetectInvalidPackDirectives:
|
||||
Enabled: true
|
||||
|
||||
Lint/ModuleDisclosureDateFormat:
|
||||
Enabled: true
|
||||
|
||||
|
|
|
@ -0,0 +1,217 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module Lint
|
||||
# Looks for invalid pack/unpack directives with Ruby 3.3.0 some directives
|
||||
# that used to not raise errors, now will - context: https://bugs.ruby-lang.org/issues/19150:
|
||||
# * Array#pack now raises ArgumentError for unknown directives
|
||||
# * String#unpack now raises ArgumentError for unknown directives
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# ```
|
||||
# 3.3.0-preview1 :003 > [0x1].pack('<L')
|
||||
# <internal:pack>:8:in `pack': unknown pack directive '<' in '<L' (ArgumentError)
|
||||
# ```
|
||||
#
|
||||
# # good
|
||||
# ```
|
||||
# 3.3.0-preview1 :001 > [0x1].pack('L<')
|
||||
# => "\x01\x00\x00\x00"
|
||||
# ```
|
||||
class DetectInvalidPackDirectives < RuboCop::Cop::Base
|
||||
# https://github.com/ruby/ruby/blob/7cfabe1acc55b24fc2c479a87efa71cf74e9e8fc/pack.c#L38
|
||||
MODIFIABLE_DIRECTIVES = %w[s S i I l L q Q j J]
|
||||
|
||||
# https://github.com/ruby/ruby/blob/7cfabe1acc55b24fc2c479a87efa71cf74e9e8fc/pack.c#L298
|
||||
ACCEPTABLE_DIRECTIVES = %w[U m A B H a A Z b B h H c C s S i I l L q Q j J n N v V f F e E d D g G x X @ % U u m M P p w]
|
||||
|
||||
# @param [RuboCop::AST::SendNode] node Node for the ruby `send` method
|
||||
# @return [[RuboCop::AST::Node], raise] offense when an invalid directive is found, or raise if unexpected error found
|
||||
def on_send(node)
|
||||
_callee, method_name = *node
|
||||
|
||||
return unless %i[pack unpack pack1 unpack1].include?(method_name)
|
||||
|
||||
args = node.arguments
|
||||
return if args.empty?
|
||||
|
||||
args.each do |arg|
|
||||
next unless string_arg?(arg)
|
||||
|
||||
# if multiline arguments are passed
|
||||
if arg.type == :dstr
|
||||
idx = []
|
||||
|
||||
pack_directive = arg.children.map do |child|
|
||||
if begin_arg?(child)
|
||||
next
|
||||
else
|
||||
idx << child.children.first.length
|
||||
child.children.join
|
||||
end
|
||||
end.join
|
||||
|
||||
# elsif single line arguments are passed
|
||||
elsif arg.type == :str
|
||||
pack_directive = arg.children.first
|
||||
end
|
||||
|
||||
error = validate_directive(pack_directive)
|
||||
if error.nil?
|
||||
next
|
||||
else
|
||||
offense_range = get_error_range(arg, error[:index], idx)
|
||||
return if offense_range.nil?
|
||||
|
||||
add_offense(offense_range, message: error[:message])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Check if the pack directives are valid. See link for pack docs https://apidock.com/ruby/Array/pack
|
||||
#
|
||||
# Code based on https://github.com/ruby/ruby/blob/6391132c03ac08da0483adb986ff9a54e41f9e14/pack.c#L196
|
||||
# adapted into Ruby
|
||||
#
|
||||
# @param [String] pack_directive The ruby pack/unpack directive to validate
|
||||
# @return [Hash,nil] A hash with the message and index that the invalidate directive was found at, or nil.
|
||||
def validate_directive(pack_directive)
|
||||
# current pointer value
|
||||
p = 0
|
||||
|
||||
# end of pointer range
|
||||
pend = pack_directive.length
|
||||
|
||||
while p < pend
|
||||
explicit_endian = 0
|
||||
type_index = p
|
||||
|
||||
# get data type
|
||||
type = pack_directive[type_index]
|
||||
p += 1
|
||||
|
||||
if type.blank?
|
||||
next
|
||||
end
|
||||
|
||||
if type == '#'
|
||||
p += 1 while p < pend && pack_directive[p] != "\n"
|
||||
next
|
||||
end
|
||||
|
||||
# Modifiers
|
||||
loop do
|
||||
case pack_directive[p]
|
||||
when '_', '!'
|
||||
if MODIFIABLE_DIRECTIVES.include?(type)
|
||||
p += 1
|
||||
else
|
||||
return { message: "'#{pack_directive[p]}' allowed only after types #{MODIFIABLE_DIRECTIVES.join}", index: p }
|
||||
end
|
||||
when '<', '>'
|
||||
unless MODIFIABLE_DIRECTIVES.include?(type)
|
||||
return { message: "'#{pack_directive[p]}' allowed only after types #{MODIFIABLE_DIRECTIVES.join}", index: p }
|
||||
end
|
||||
|
||||
if explicit_endian != 0
|
||||
return { message: "Can't use both '<' and '>'.", index: p }
|
||||
end
|
||||
|
||||
explicit_endian = pack_directive[p]
|
||||
p += 1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
# Data length
|
||||
if pack_directive[p] == '*'
|
||||
p += 1
|
||||
elsif pack_directive[p]&.match?(/\d/)
|
||||
p += 1 while pack_directive[p]&.match?(/\d/)
|
||||
end
|
||||
|
||||
# Check type
|
||||
unless ACCEPTABLE_DIRECTIVES.include?(type)
|
||||
return { message: "unknown pack directive '#{type}' in '#{pack_directive}'", index: type_index }
|
||||
end
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
# Checks if the current node is of type `:str` or `:dstr` - `dstr` being multiline
|
||||
#
|
||||
# @param [RuboCop::AST::SendNode] node Node for the ruby `send` method
|
||||
# @return [TrueClass, FalseClass]
|
||||
def string_arg?(node)
|
||||
node&.type == :str || node&.type == :dstr
|
||||
end
|
||||
|
||||
# Check if the node if of type `:begin`
|
||||
#
|
||||
# @param [RuboCop::AST::SendNode] node Node for the ruby `send` method
|
||||
# @return [TrueClass, FalseClass]
|
||||
def begin_arg?(node)
|
||||
node.type == :begin
|
||||
end
|
||||
|
||||
# Get the range of the offense to more accurately raise offenses against specific directives
|
||||
#
|
||||
# @param [RuboCop::AST::DstrNode, RuboCop::AST::StrNode ] arg The node that need its range calculated
|
||||
# @param [Integer] p The current pointer value
|
||||
# @param [Array] idx An array holding to number of indexes for the node
|
||||
# @return [Parser::Source::Range] The range of the node value
|
||||
def get_error_range(arg, p, idx)
|
||||
# Logic for multiline strings
|
||||
if arg.type == :dstr
|
||||
total = 0
|
||||
index = 0
|
||||
|
||||
idx.each_with_index do |idx_length, count|
|
||||
if total < p
|
||||
total += idx_length
|
||||
index = count
|
||||
end
|
||||
end
|
||||
adjusted_index = p - idx[0..(index - 1)].sum
|
||||
|
||||
indexed_arg = arg.children[index]
|
||||
|
||||
if begin_arg?(indexed_arg)
|
||||
return nil
|
||||
else
|
||||
newline_adjustment = indexed_arg.children.first[0..adjusted_index].scan(/[\n\t]/).count
|
||||
end
|
||||
|
||||
# If there's opening quotes present, i.e. "a", instead of heredoc which doesn't have preceding opening quotes:
|
||||
if indexed_arg.loc.begin
|
||||
range_start = indexed_arg.loc.begin.end_pos + (p - adjusted_index)
|
||||
else
|
||||
expression = processed_source.raw_source[indexed_arg.loc.expression.begin.begin_pos...indexed_arg.loc.expression.end.end_pos]
|
||||
if expression[/^\s+/].nil?
|
||||
leading_whitespace_size = 0
|
||||
else
|
||||
leading_whitespace_size = expression[/^\s+/].length
|
||||
end
|
||||
adjusted_index += leading_whitespace_size
|
||||
range_start = indexed_arg.loc.expression.begin_pos + (adjusted_index + newline_adjustment)
|
||||
end
|
||||
# Logic for single line strings
|
||||
else
|
||||
newline_adjustment = arg.children.first[0..p].scan(/[\n\t]/).count
|
||||
range_start = arg.loc.begin.end_pos + (p + newline_adjustment)
|
||||
end
|
||||
|
||||
range_end = range_start + 1
|
||||
|
||||
Parser::Source::Range.new(arg.loc.expression.source_buffer, range_start, range_end)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,850 @@
|
|||
require 'spec_helper'
|
||||
require 'rubocop/cop/lint/detect_invalid_pack_directives'
|
||||
|
||||
RSpec.describe RuboCop::Cop::Lint::DetectInvalidPackDirectives do
|
||||
subject(:cop) { described_class.new(config) }
|
||||
let(:empty_rubocop_config) { {} }
|
||||
let(:config) { RuboCop::Config.new(empty_rubocop_config) }
|
||||
let(:pack_directive) { "Q<" }
|
||||
let(:pack_amount) { 2 }
|
||||
let(:endian) {:little}
|
||||
let(:packstr) {(endian == :little) ? 'v' : 'n'}
|
||||
|
||||
context 'when passed an unknown pack/unpacks directive' do
|
||||
it 'detects the invalid directive' do
|
||||
expect_offense(<<~RUBY)
|
||||
[10].pack('_I')
|
||||
^ unknown pack directive '_' in '_I'
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'detects the invalid directive' do
|
||||
expect_offense(<<~RUBY)
|
||||
[10].pack('<L<L<Q<Q<Q<La*<L<Q<Q<Q<Q<Q<Q<L<L<Q<L<L')
|
||||
^ unknown pack directive '<' in '<L<L<Q<Q<Q<La*<L<Q<Q<Q<Q<Q<Q<L<L<Q<L<L'
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'detects the invalid directive' do
|
||||
expect_offense(<<~RUBY)
|
||||
[10].pack('<123456')
|
||||
^ unknown pack directive '<' in '<123456'
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'detects the invalid directive' do
|
||||
expect_offense(<<~RUBY)
|
||||
[10].pack('<')
|
||||
^ unknown pack directive '<' in '<'
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'detects the invalid directive' do
|
||||
expect_offense(<<~RUBY)
|
||||
[10].pack('<s')
|
||||
^ unknown pack directive '<' in '<s'
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'detects the invalid directive' do
|
||||
expect_offense(<<~RUBY)
|
||||
[0x0123456789ABCDEF, 'foo'].pack('<Qa*')
|
||||
^ unknown pack directive '<' in '<Qa*'
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'detects the invalid directive' do
|
||||
expect_offense(<<~RUBY)
|
||||
[112].pack('<I')
|
||||
^ unknown pack directive '<' in '<I'
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'detects the invalid directive' do
|
||||
expect_offense(<<~RUBY)
|
||||
[1].pack('<ISSSSI')
|
||||
^ unknown pack directive '<' in '<ISSSSI'
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'detects the invalid directive' do
|
||||
expect_offense(<<~RUBY)
|
||||
[200].pack('<L')
|
||||
^ unknown pack directive '<' in '<L'
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'detects the invalid directive' do
|
||||
expect_offense(<<~RUBY)
|
||||
[400].pack('<S<S')
|
||||
^ unknown pack directive '<' in '<S<S'
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'detects the invalid directive' do
|
||||
expect_offense(<<~RUBY)
|
||||
"foo".unpack("*V")
|
||||
^ unknown pack directive '*' in '*V'
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'detects the invalid directive' do
|
||||
expect_offense(<<~RUBY)
|
||||
"foo".unpack("D<")
|
||||
^ '<' allowed only after types sSiIlLqQjJ
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'detects the invalid directive' do
|
||||
expect_offense(<<~RUBY)
|
||||
"foo".unpack(%q{D<})
|
||||
^ '<' allowed only after types sSiIlLqQjJ
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'detects the invalid directive' do
|
||||
expect_offense(<<~'RUBY')
|
||||
"foo".unpack("\tD<")
|
||||
^ '<' allowed only after types sSiIlLqQjJ
|
||||
RUBY
|
||||
end
|
||||
end
|
||||
|
||||
context 'when passed multiline strings with invalid pack/unpacks directives' do
|
||||
it 'ignores comments in the format string and detects the invalid directive' do
|
||||
expect_offense(<<~RUBY)
|
||||
[9.3, 4.7].pack <<~EOF
|
||||
# The first decimal value
|
||||
D # first inline comment
|
||||
# The second decimal value
|
||||
D< # The second inline comment
|
||||
^ '<' allowed only after types sSiIlLqQjJ
|
||||
# Final comment
|
||||
EOF
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'ignores comments in the format string and detects the invalid directive' do
|
||||
expect_offense(<<~RUBY)
|
||||
[9.3, 4.7].pack <<~EOF
|
||||
# The first decimal value
|
||||
D # first inline comment
|
||||
# The second decimal value
|
||||
D< # The second inline comment
|
||||
^ '<' allowed only after types sSiIlLqQjJ
|
||||
# Final comment
|
||||
EOF
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'ignores comments in the format string and detects the invalid directive' do
|
||||
expect_offense(<<~RUBY)
|
||||
[9.3, 4.7].pack <<~EOF
|
||||
# The first decimal value
|
||||
D # first inline comment
|
||||
# The second decimal value
|
||||
D< # The second inline comment
|
||||
^ '<' allowed only after types sSiIlLqQjJ
|
||||
# Final comment
|
||||
EOF
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'ignores comments in the format string and detects the invalid directive' do
|
||||
expect_offense(<<~'RUBY')
|
||||
[1,2,3].pack("D# some comment \nD# some comment \n# some comment \nD>")
|
||||
^ '>' allowed only after types sSiIlLqQjJ
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'ignores comments in the format string and detects the invalid directive' do
|
||||
expect_offense(<<~'RUBY')
|
||||
[1,2,3].pack("D># some comment \nD# some comment \n# some comment \nD")
|
||||
^ '>' allowed only after types sSiIlLqQjJ
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'ignores comments in the format string and detects the invalid directive' do
|
||||
expect_offense(<<~'RUBY')
|
||||
[9.3, 4.7].pack("D# some comment \nD<")
|
||||
^ '<' allowed only after types sSiIlLqQjJ
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'raises an offense' do
|
||||
expect_offense(<<-'RUBY')
|
||||
[10].pack(
|
||||
"Q" \
|
||||
"D<"
|
||||
^ '<' allowed only after types sSiIlLqQjJ
|
||||
)
|
||||
RUBY
|
||||
end
|
||||
end
|
||||
|
||||
context 'when passed string interpolation' do
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[1, 2].pack("@1#{'XV' * (2 * 2)}")
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<-'RUBY')
|
||||
[9, 4].pack("@1#{'XV' * (pack_amount * pack_amount)}")
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<-'RUBY')
|
||||
[9, 4].pack("I<c#{pack_amount}")
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<-'RUBY')
|
||||
"\t\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00".unpack("#{pack_directive}@1")
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<-'RUBY')
|
||||
options[idx, 4].unpack("#{packstr}2")
|
||||
RUBY
|
||||
end
|
||||
end
|
||||
|
||||
it 'raises an offense' do
|
||||
expect_no_offenses(<<-'RUBY')
|
||||
"\t\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00".unpack("#{pack_directive}*")
|
||||
RUBY
|
||||
end
|
||||
|
||||
context 'when passed valid pack/unpacks directives' do
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
"a\x10\x10\x10".unpack('nCCnnQ>')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
['abc'].pack('h3')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[1, 2].pack("C@3C")
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
['a' * 123].pack('h123')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
['abc', 'a'].pack('h3h')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('C')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('S')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('L')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('Q')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('J')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('c')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('s')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('l')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('q')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('j')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('S_')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('S!')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('I')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('J')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('I_')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('I!')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('L_')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('L!')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('Q_')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('Q!')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('J!')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('s_')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('s!')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('i')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('i_')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('i!')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('l')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('l!')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('q_')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('q!')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('j!')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('S>')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('s>')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('S!>')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('s!>')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('L>')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('l>')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('L!>')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('l!>')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('I!>')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('i!>')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('Q>')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('q>')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('Q!>')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('q!>')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('J>')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('j>')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('J!>')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('j!>')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('S<')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('s<')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('S!<')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('s!<')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('L<')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('l<')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('L!<')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('l!<')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('I!<')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('i!<')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('Q<')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('q<')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('Q!<')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('q!<')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('J<')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('j<')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('J!<')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('j!<')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('n')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('N')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('v')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('V')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('U')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack('w')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10.10].pack('D')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10.10].pack('d')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10.10].pack('F')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10.10].pack('f')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10.10].pack('E')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10.10].pack('e')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10.10].pack('G')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10.10].pack('g')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
['test'].pack('A')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
['test'].pack('a')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
['test'].pack('Z')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
['test'].pack('B')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
['test'].pack('b')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
['test'].pack('H')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
['test'].pack('h')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
['test'].pack('u')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
['test'].pack('M')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
['test'].pack('m')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
['test'].pack('p')
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
['test'].pack('P')
|
||||
RUBY
|
||||
end
|
||||
end
|
||||
|
||||
context 'when passed multiline strings with valid pack/unpacks directives' do
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[9.3, 4.7].pack <<~EOF
|
||||
# The first decimal value
|
||||
D # first inline comment
|
||||
# The second decimal value
|
||||
S< # The second inline comment
|
||||
# Final comment
|
||||
EOF
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not raise an offence' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[10].pack(
|
||||
"Q" \
|
||||
"L"
|
||||
)
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'raises an offense' do
|
||||
expect_no_offenses(<<-'RUBY')
|
||||
[10].pack(
|
||||
"Q" \
|
||||
"<L"
|
||||
)
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'ignores comments in the format string and detects the invalid directive' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
[9.3, 4.7].pack("D# some comment S<")
|
||||
RUBY
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue