From c0797b9a7b8d563e04534ce9ebcba827ab3f9356 Mon Sep 17 00:00:00 2001 From: Jeremy Bopp Date: Sun, 18 Dec 2016 11:16:15 -0600 Subject: [PATCH] Fix initialization of DOSTime when given a nil * Add validation for given time structure * Add tests for validation * Closes #17 --- lib/archive/support/time.rb | 31 +++++++++- spec/archive/dos_time_spec.rb | 113 ++++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 spec/archive/dos_time_spec.rb diff --git a/lib/archive/support/time.rb b/lib/archive/support/time.rb index 85cd4ef..7c266b1 100644 --- a/lib/archive/support/time.rb +++ b/lib/archive/support/time.rb @@ -45,7 +45,7 @@ class DOSTime def initialize(dos_time = nil) case dos_time when nil - @dos_time = Time.now.to_dos_time.dos_time + @dos_time = Time.now.to_dos_time.to_i when Integer @dos_time = dos_time else @@ -54,6 +54,8 @@ def initialize(dos_time = nil) end @dos_time = dos_time.unpack('V')[0] end + + validate end # Returns -1 if _other_ is a time earlier than this one, 0 if _other_ is the @@ -86,5 +88,32 @@ def to_time year = ((0b1111111 << 25 & @dos_time) >> 25) + 1980 return Time.local(year, month, day, hour, minute, second) end + + private + + def validate + second = (0b11111 & @dos_time) + minute = (0b111111 << 5 & @dos_time) >> 5 + hour = (0b11111 << 11 & @dos_time) >> 11 + day = (0b11111 << 16 & @dos_time) >> 16 + month = (0b1111 << 21 & @dos_time) >> 21 + year = (0b1111111 << 25 & @dos_time) >> 25 + + if second > 29 + raise ArgumentError, 'second must not be greater than 29' + elsif minute > 59 + raise ArgumentError, 'minute must not be greater than 59' + elsif hour > 24 + raise ArgumentError, 'hour must not be greater than 24' + elsif day < 1 + raise ArgumentError, 'day must not be less than 1' + elsif month < 1 + raise ArgumentError, 'month must not be less than 1' + elsif month > 12 + raise ArgumentError, 'month must not be greater than 12' + elsif year > 119 + raise ArgumentError, 'year must not be greater than 119' + end + end end end diff --git a/spec/archive/dos_time_spec.rb b/spec/archive/dos_time_spec.rb new file mode 100644 index 0000000..0d73480 --- /dev/null +++ b/spec/archive/dos_time_spec.rb @@ -0,0 +1,113 @@ +# encoding: UTF-8 + +require 'minitest/autorun' + +require 'archive/support/time' + +describe 'Archive::DOSTime.new' do + let(:epoc) { 0b0000000_0001_00001_00000_000000_00000 } + let(:end_times) { 0b1110111_1100_11111_11000_111011_11101 } + + it 'uses the current time when no structure is given' do + now = Time.now.localtime + dos_time = Archive::DOSTime.new.to_time + + now.year.must_be_close_to(dos_time.year, 1) + now.month.must_be_close_to(dos_time.month, 1) + now.day.must_be_close_to(dos_time.day, 1) + now.hour.must_be_close_to(dos_time.hour, 1) + now.min.must_be_close_to(dos_time.min, 1) + now.sec.must_be_close_to(dos_time.sec, 3) + end + + it 'accepts valid Integer structures' do + Archive::DOSTime.new(epoc) + Archive::DOSTime.new(end_times) + end + + it 'accepts valid String structures' do + Archive::DOSTime.new([epoc].pack('V')) + Archive::DOSTime.new([end_times].pack('V')) + end + + it 'rejects invalid Integer structures' do + # Second must not be greater than 29. + proc { + Archive::DOSTime.new(epoc | 0b0000000_0000_00000_00000_000000_11110) + }.must_raise(ArgumentError) + + # Minute must not be greater than 59. + proc { + Archive::DOSTime.new(epoc | 0b0000000_0000_00000_00000_111100_00000) + }.must_raise(ArgumentError) + + # Hour must not be greater than 24. + proc { + Archive::DOSTime.new(epoc | 0b0000000_0000_00000_11001_000000_00000) + }.must_raise(ArgumentError) + + # Day must not be zero. + proc { + Archive::DOSTime.new(epoc & 0b1111111_1111_00000_11111_111111_11111) + }.must_raise(ArgumentError) + + # Month must not be zero. + proc { + Archive::DOSTime.new(epoc & 0b1111111_0000_11111_11111_111111_11111) + }.must_raise(ArgumentError) + + # Month must not be greater than 12. + proc { + Archive::DOSTime.new(epoc | 0b0000000_1101_00000_00000_000000_00000) + }.must_raise(ArgumentError) + + # Year must not be greater than 119. + proc { + Archive::DOSTime.new(epoc | 0b1111000_0000_00000_00000_000000_00000) + }.must_raise(ArgumentError) + end + + it 'rejects invalid String structures' do + # Second must not be greater than 29. + proc { + packed = [epoc | 0b0000000_0000_00000_00000_000000_11110].pack('V') + Archive::DOSTime.new(packed) + }.must_raise(ArgumentError) + + # Minute must not be greater than 59. + proc { + packed = [epoc | 0b0000000_0000_00000_00000_111100_00000].pack('V') + Archive::DOSTime.new(packed) + }.must_raise(ArgumentError) + + # Hour must not be greater than 24. + proc { + packed = [epoc | 0b0000000_0000_00000_11001_000000_00000].pack('V') + Archive::DOSTime.new(packed) + }.must_raise(ArgumentError) + + # Day must not be zero. + proc { + packed = [epoc & 0b1111111_1111_00000_11111_111111_11111].pack('V') + Archive::DOSTime.new(packed) + }.must_raise(ArgumentError) + + # Month must not be zero. + proc { + packed = [epoc & 0b1111111_0000_11111_11111_111111_11111].pack('V') + Archive::DOSTime.new(packed) + }.must_raise(ArgumentError) + + # Month must not be greater than 12. + proc { + packed = [epoc | 0b0000000_1101_00000_00000_000000_00000].pack('V') + Archive::DOSTime.new(packed) + }.must_raise(ArgumentError) + + # Year must not be greater than 119. + proc { + packed = [epoc | 0b1111000_0000_00000_00000_000000_00000].pack('V') + Archive::DOSTime.new(packed) + }.must_raise(ArgumentError) + end +end