tinycode 0.1.1 → 0.2.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 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: