tinycode 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3438fb3aab3c2d58592ed6c9bc1f63f37e98effbecb60a67f110d4306a3822aa
4
- data.tar.gz: 65b47a8b537de5b3e40b6c0dfd7efd5789135e2ae71d463df1e372cc697eb436
3
+ metadata.gz: 1e5a75ffceb25e155db277a905e940cbf22a3f43a666113aede98b5457176aca
4
+ data.tar.gz: f095520fdf8e46c939f7937957fb831951118d11ebef414a8d08bbee86b1a331
5
5
  SHA512:
6
- metadata.gz: 2214f092bbbc76b3daa8f694a2ddf04556ae80a5627cb80e0060ad25b842ad431c948a828e1d0f0dcb29ab1a3dc8171e3f8ca81a4c9f1f66b3495074dfd126fd
7
- data.tar.gz: b9824631c29c06ec9fd66b1e127f9a3c35c5956ee4514758c07b3290317a253609a36d73201795686ea419fb0a86444ed043e353d3397d2ecf279435a40c4d3a
6
+ metadata.gz: 5146523a4517a8effb28f426c6922cb0338ec6a66de0a545b75385551e9a2ed0158e5292f8af441f15c1888cff7deb99e6e9550e029f26e3e7e5a16519a80255
7
+ data.tar.gz: 0ad1a83f8c3f5d2a3ddbe5639d23e618a3dc4988825740d52ded2077188b5c373ce644b75b829be49fa0128fdad705fa690cc6b1107e4b0a0427361c3691bfa8
data/.rubocop.yml CHANGED
@@ -32,6 +32,8 @@ Metrics/BlockLength:
32
32
 
33
33
  RSpec/MultipleExpectations:
34
34
  Enabled: false
35
+ RSpec/ExampleLength:
36
+ Max: 10
35
37
 
36
38
  Style/AsciiComments:
37
39
  Enabled: false
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- tinycode (0.1.1)
4
+ tinycode (0.2.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -14,14 +14,14 @@ GEM
14
14
  rb-fsevent (~> 0.10, >= 0.10.3)
15
15
  rb-inotify (~> 0.9, >= 0.9.10)
16
16
  parallel (1.21.0)
17
- parser (3.0.2.0)
17
+ parser (3.0.3.1)
18
18
  ast (~> 2.4.1)
19
19
  rainbow (3.0.0)
20
20
  rake (13.0.6)
21
21
  rb-fsevent (0.11.0)
22
22
  rb-inotify (0.10.1)
23
23
  ffi (~> 1.0)
24
- regexp_parser (2.1.1)
24
+ regexp_parser (2.2.0)
25
25
  rerun (0.13.1)
26
26
  listen (~> 3.0)
27
27
  rexml (3.2.5)
@@ -47,7 +47,7 @@ GEM
47
47
  rubocop-ast (>= 1.12.0, < 2.0)
48
48
  ruby-progressbar (~> 1.7)
49
49
  unicode-display_width (>= 1.4.0, < 3.0)
50
- rubocop-ast (1.13.0)
50
+ rubocop-ast (1.14.0)
51
51
  parser (>= 3.0.1.1)
52
52
  rubocop-rake (0.6.0)
53
53
  rubocop (~> 1.0)
@@ -61,10 +61,13 @@ GEM
61
61
  simplecov-html (0.12.3)
62
62
  simplecov_json_formatter (0.1.3)
63
63
  unicode-display_width (2.1.0)
64
- yard (0.9.26)
64
+ webrick (1.7.0)
65
+ yard (0.9.27)
66
+ webrick (~> 1.7.0)
65
67
 
66
68
  PLATFORMS
67
69
  x86_64-darwin-19
70
+ x86_64-linux
68
71
 
69
72
  DEPENDENCIES
70
73
  rake (~> 13.0)
data/README.md CHANGED
@@ -85,13 +85,13 @@ gem 'tinycode'
85
85
  And then execute:
86
86
 
87
87
  ```sh
88
- $ bundle install
88
+ bundle install
89
89
  ```
90
90
 
91
91
  Or install it yourself as:
92
92
 
93
93
  ```sh
94
- $ gem install tinycode
94
+ gem install tinycode
95
95
  ```
96
96
 
97
97
  ## Usage
@@ -148,8 +148,7 @@ copyright dates.
148
148
 
149
149
  This program is free software: you can redistribute it and/or modify
150
150
  it under the terms of the GNU General Public License as published by
151
- the Free Software Foundation, either version 3 of the License, or
152
- (at your option) any later version.
151
+ the Free Software Foundation, version 3.
153
152
 
154
153
  This program is distributed in the hope that it will be useful,
155
154
  but WITHOUT ANY WARRANTY; without even the implied warranty of
data/Rakefile CHANGED
@@ -12,8 +12,13 @@ RuboCop::RakeTask.new(:lint) do |task|
12
12
  end
13
13
  YARD::Rake::YardocTask.new
14
14
 
15
- task :watch do
16
- sh 'rerun -p "{**/*.{rb,gemspec},exe/**/*,Gemfile*,Rakefile}" -x rake yard spec lint:auto_correct'
15
+ task :dev do
16
+ sh 'bundle install'
17
+ sh 'rerun -p "{**/*.{rb,gemspec},exe/**/*,Gemfile*,Rakefile}" -x rake yard spec'
18
+ end
19
+
20
+ task :autofixlint do
21
+ sh 'rerun -p "{**/*.{rb,gemspec},exe/**/*,Gemfile*,Rakefile}" -x rake lint:auto_correct'
17
22
  end
18
23
 
19
24
  task default: [:spec, :lint]
data/bin/acid_test.rb ADDED
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+ require_relative '../lib/tinycode'
5
+
6
+ ITERATIONS = 100_000
7
+ MAX_INPUT_LENGTH = 4096
8
+
9
+ MAX_INPUT_LENGTH.times do |input_length|
10
+ results = []
11
+ ITERATIONS.times do
12
+ input = SecureRandom.bytes(input_length)
13
+ begin
14
+ Tinycode.load(input)
15
+ results << 'Success'
16
+ rescue Tinycode::ParseError => e
17
+ results <<
18
+ if e.message =~ /\AUnexpected character: /
19
+ 'Unexpected character: ...'
20
+ else
21
+ e.message
22
+ end
23
+ rescue Error
24
+ warn "Attempted to parse #{input.inspect} but got unexpected error:"
25
+ raise
26
+ end
27
+ end
28
+ puts "==== For inputs of length #{input_length}:"
29
+ results.tally.to_a.sort_by(&:last).each do |result, times|
30
+ puts "#{result} x#{times}"
31
+ end
32
+ puts
33
+ end
34
+
35
+ puts "Congratulations! Was unable to find a vector that results in an unexpected error for sizes <= #{MAX_INPUT_LENGTH}"
@@ -28,17 +28,25 @@ module Tinycode
28
28
  end
29
29
 
30
30
  def load(tinycode)
31
- raise ArgumentError, "Cannot convert #{tinycode.class} to String" if !tinycode.respond_to?(:to_str)
32
-
33
- tinycode = tinycode.to_str.b
31
+ tinycode = implicitly_convert_str(tinycode).b
34
32
  struct, length = load_with_length(tinycode)
35
- raise ParseError, 'Input is longer than expected' if length != tinycode.length
33
+ raise 'a load_ implementation claims it read past the end of stream!' if length > tinycode.length
34
+ raise ParseError, 'Stream is longer than expected' if length < tinycode.length
36
35
 
37
36
  struct
38
37
  end
39
38
 
40
39
  private
41
40
 
41
+ def implicitly_convert_str(obj)
42
+ raise ArgumentError, "Cannot convert #{obj.class} to String" if !obj.respond_to?(:to_str)
43
+
44
+ str = obj.to_str
45
+ raise ArgumentError, "#{obj.class}#to_str did not return String, got #{str.class}" if !str.is_a?(String)
46
+
47
+ str
48
+ end
49
+
42
50
  def load_with_length(tinycode)
43
51
  case tinycode[0]
44
52
  when /[\w \t\n]/ then load_id(tinycode)
@@ -53,7 +61,8 @@ module Tinycode
53
61
  when '#' then load_fixed_integer(tinycode, U64, length: 8, unpack: 'Q>')
54
62
  when "\0" then [nil, 1]
55
63
  when '?' then load_boolean(tinycode)
56
- else raise ParseError, "Unexpected character: #{tinycode[0]}"
64
+ when nil then raise ParseError, 'Unexpected end of stream'
65
+ else raise ParseError, "Unexpected character: #{tinycode[0].inspect}"
57
66
  end
58
67
  end
59
68
 
@@ -93,7 +102,7 @@ module Tinycode
93
102
 
94
103
  def dump_string(str, code: "'")
95
104
  str = str.encode('UTF-8').b unless str.encoding == Encoding::ASCII_8BIT
96
- if str =~ /\A[\w \t\n]+\z/
105
+ if str =~ /\A[\w \t\n][^':]*\z/
97
106
  [str, code].pack('a*a')
98
107
  else
99
108
  [code, str.length, str].pack('awa*')
@@ -102,18 +111,23 @@ module Tinycode
102
111
 
103
112
  def load_id(tinycode)
104
113
  length = tinycode.index(/[':]/)
105
- value = tinycode[0...length]
106
- value = if tinycode[length] == ':'
107
- value.to_sym
108
- else
109
- value.force_encoding('UTF-8')
110
- end
114
+ raise ParseError, 'Unexpected end of stream' if !length
115
+
116
+ value = tinycode[0...length].force_encoding('UTF-8')
117
+ raise ParseError, 'invalid byte sequence in UTF-8 string' if !value.valid_encoding?
118
+
119
+ value = value.to_sym if tinycode[length] == ':'
111
120
  [value, length + 1]
112
121
  end
113
122
 
114
123
  def load_string(tinycode)
115
124
  str_length, offset = load_varint(tinycode[1..])
116
- [tinycode[(1 + offset)...(1 + offset + str_length)].force_encoding('UTF-8'), 1 + offset + str_length]
125
+ raise ParseError, 'Unexpected end of stream' if tinycode.length < 1 + offset + str_length
126
+
127
+ str = tinycode[(1 + offset)...(1 + offset + str_length)].force_encoding('UTF-8')
128
+ raise ParseError, 'invalid byte sequence in UTF-8 string' if !str.valid_encoding?
129
+
130
+ [str, 1 + offset + str_length]
117
131
  end
118
132
 
119
133
  def dump_symbol(sym)
@@ -136,6 +150,7 @@ module Tinycode
136
150
  def load_integer(tinycode)
137
151
  value, offset = load_varint(tinycode[1..])
138
152
  value = -value if tinycode[0] == '-'
153
+ raise ParseError, '-0 is not a valid integer' if value == 0 && tinycode[0] == '-'
139
154
 
140
155
  [value, 1 + offset]
141
156
  end
@@ -145,11 +160,15 @@ module Tinycode
145
160
  end
146
161
 
147
162
  def load_fixed_integer(tinycode, clazz, length:, unpack:)
163
+ raise ParseError, 'Unexpected end of stream' if tinycode.length < length + 1
164
+
148
165
  [clazz.new(tinycode[1...(1 + length)].unpack1(unpack)), 1 + length]
149
166
  end
150
167
 
151
168
  def load_varint(tinycode)
152
169
  length = tinycode.each_byte.lazy.take_while {|b| b > 0x7F }.count + 1
170
+ raise ParseError, 'Unexpected end of stream' if length > tinycode.length
171
+
153
172
  [tinycode[0...length].unpack1('w'), length]
154
173
  end
155
174
 
@@ -157,7 +176,7 @@ module Tinycode
157
176
  case tinycode[1]
158
177
  when 'T' then [true, 2]
159
178
  when 'F' then [false, 2]
160
- else raise ParseError, 'Malformed boolean'
179
+ else raise ParseError, 'Malformed boolean value'
161
180
  end
162
181
  end
163
182
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tinycode
4
- VERSION = '0.1.1'
4
+ VERSION = '0.2.0'
5
5
  end
data/tinycode.gemspec CHANGED
@@ -3,20 +3,24 @@
3
3
  require_relative 'lib/tinycode/version'
4
4
 
5
5
  Gem::Specification.new do |spec|
6
- spec.name = 'tinycode'
7
- spec.version = Tinycode::VERSION
8
- spec.summary = 'An encoder and decoder for tinycode'
9
- spec.description = 'tinycode is a bencode like encoding that supports more ' \
10
- 'data-types and slightly smaller encoded sizes.'
11
- spec.authors = ['Alex Gittemeier']
12
- spec.license = 'GPL-3.0'
13
- spec.email = ['me@a.lexg.dev']
14
- spec.metadata['source_code_uri'] = 'https://gitlab.com/windows93/tinycode'
15
- spec.metadata['rubygems_mfa_required'] = 'true'
16
- # spec.metadata['changelog_uri'] =
6
+ spec.name = 'tinycode'
7
+ spec.version = Tinycode::VERSION
8
+ spec.summary = 'An encoder and decoder for tinycode'
9
+ spec.description = <<~DESCRIPTION
10
+ tinycode is a bencode like encoding that supports more data-types
11
+ and slightly smaller encoded sizes.
12
+ DESCRIPTION
13
+ spec.author = 'Alex Gittemeier'
14
+ spec.email = 'me@a.lexg.dev'
15
+ spec.license = 'GPL-3.0-only'
17
16
 
18
- spec.homepage = spec.metadata['source_code_uri']
19
- spec.metadata['homepage_uri'] = spec.homepage
17
+ spec.metadata['homepage_uri'] = 'https://gitlab.com/windows93/tinycode'
18
+ spec.metadata['source_code_uri'] = 'https://gitlab.com/windows93/tinycode/-/tree/stable'
19
+ spec.metadata['documentation_uri'] = 'https://www.rubydoc.info/gems/tinycode/'
20
+ spec.metadata['bug_tracker_uri'] = 'https://gitlab.com/windows93/tinycode/-/issues'
21
+ spec.metadata['changelog_uri'] = 'https://gitlab.com/windows93/tinycode/-/commits/stable'
22
+ spec.metadata['rubygems_mfa_required'] = 'true'
23
+ spec.homepage = spec.metadata['homepage_uri']
20
24
 
21
25
  # Specify which files should be added to the gem when it is released.
22
26
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -25,9 +29,6 @@ Gem::Specification.new do |spec|
25
29
  (f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
26
30
  end
27
31
  end
28
- spec.bindir = 'exe'
29
- spec.executables = spec.files.grep(%r{\Aexe/}) {|f| File.basename(f) }
30
- spec.require_paths = ['lib']
31
32
 
32
33
  spec.required_ruby_version = '>= 2.6.0'
33
34
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tinycode
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Gittemeier
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-22 00:00:00.000000000 Z
11
+ date: 2021-12-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -122,10 +122,10 @@ dependencies:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0.9'
125
- description: tinycode is a bencode like encoding that supports more data-types and
126
- slightly smaller encoded sizes.
127
- email:
128
- - me@a.lexg.dev
125
+ description: |
126
+ tinycode is a bencode like encoding that supports more data-types
127
+ and slightly smaller encoded sizes.
128
+ email: me@a.lexg.dev
129
129
  executables: []
130
130
  extensions: []
131
131
  extra_rdoc_files: []
@@ -138,6 +138,7 @@ files:
138
138
  - LICENSE
139
139
  - README.md
140
140
  - Rakefile
141
+ - bin/acid_test.rb
141
142
  - lib/tinycode.rb
142
143
  - lib/tinycode/core_ext.rb
143
144
  - lib/tinycode/fixed_integer.rb
@@ -147,11 +148,14 @@ files:
147
148
  - tinycode.gemspec
148
149
  homepage: https://gitlab.com/windows93/tinycode
149
150
  licenses:
150
- - GPL-3.0
151
+ - GPL-3.0-only
151
152
  metadata:
152
- source_code_uri: https://gitlab.com/windows93/tinycode
153
- rubygems_mfa_required: 'true'
154
153
  homepage_uri: https://gitlab.com/windows93/tinycode
154
+ source_code_uri: https://gitlab.com/windows93/tinycode/-/tree/stable
155
+ documentation_uri: https://www.rubydoc.info/gems/tinycode/
156
+ bug_tracker_uri: https://gitlab.com/windows93/tinycode/-/issues
157
+ changelog_uri: https://gitlab.com/windows93/tinycode/-/commits/stable
158
+ rubygems_mfa_required: 'true'
155
159
  post_install_message:
156
160
  rdoc_options: []
157
161
  require_paths: