Skip to content

Commit

Permalink
add base functionality and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
XenoPhex committed Feb 6, 2018
1 parent 1b0f9c1 commit cf33dab
Show file tree
Hide file tree
Showing 3 changed files with 240 additions and 5 deletions.
1 change: 1 addition & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ require "rspec/core/rake_task"
RSpec::Core::RakeTask.new(:spec)

task :default => :spec
task :test => :spec
89 changes: 88 additions & 1 deletion lib/palm_civet.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,92 @@
require "palm_civet/version"

module PalmCivet
# Your code goes here...
BYTE = 1.0
KILOBYTE = 1024 * BYTE
MEGABYTE = 1024 * KILOBYTE
GIGABYTE = 1024 * MEGABYTE
TERABYTE = 1024 * GIGABYTE
BYTESPATTERN = /^(-?\d+(?:\.\d+)?)([KMGT]i?B?|B)$/i

class InvalidByteQuantityError < RuntimeError
def initialize(msg="byte quantity must be a positive integer with a unit of measurement like M, MB, MiB, G, GiB, or GB")
super
end
end

# Returns a human-readable byte string of the form 10M, 12.5K, and so forth.
# The following units are available:
# * T: Terabyte
# * G: Gigabyte
# * M: Megabyte
# * K: Kilobyte
# * B: Byte
# The unit that results in the smallest number greater than or equal to 1 is
# always chosen.
def self.byte_size(bytes)
if !bytes.is_a? Numeric
raise TypeError, "must be an integer or float"
end

case
when bytes >= TERABYTE
unit = "T"
value = bytes / TERABYTE
when bytes >= GIGABYTE
unit = "G"
value = bytes / GIGABYTE
when bytes >= MEGABYTE
unit = "M"
value = bytes / MEGABYTE
when bytes >= KILOBYTE
unit = "K"
value = bytes / KILOBYTE
when bytes >= BYTE
unit = "B"
value = bytes
else
return "0"
end

value = "%g" % ("%.1f" % value)
return value << unit
end

# Parses a string formatted by bytes_size as bytes. Note binary-prefixed and
# SI prefixed units both mean a base-2 units:
# * KB = K = KiB = 1024
# * MB = M = MiB = 1024 * K
# * GB = G = GiB = 1024 * M
# * TB = T = TiB = 1024 * G
def self.to_bytes(bytes)
matches = BYTESPATTERN.match(bytes.strip)
if matches == nil
raise InvalidByteQuantityError
end

value = Float(matches[1])
if value <= 0
raise InvalidByteQuantityError
end

case matches[2][0].capitalize
when "T"
value = value * TERABYTE
when "G"
value = value * GIGABYTE
when "M"
value = value * MEGABYTE
when "K"
value = value * KILOBYTE
end

return value.to_i
rescue TypeError
raise InvalidByteQuantityError
end

# Parses a string formatted by byte_size as megabytes.
def self.to_megabytes(bytes)
(self.to_bytes(bytes) / MEGABYTE).to_i
end
end
155 changes: 151 additions & 4 deletions spec/palm_civet_spec.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,156 @@
RSpec.describe PalmCivet do
it "has a version number" do
expect(PalmCivet::VERSION).not_to be nil
describe "#byte_size" do
it "prints in the largest possible unit" do
expect(PalmCivet.byte_size(10 * PalmCivet::TERABYTE)).to eq("10T")
expect(PalmCivet.byte_size(10.5 * PalmCivet::TERABYTE)).to eq("10.5T")

expect(PalmCivet.byte_size(10 * PalmCivet::GIGABYTE)).to eq("10G")
expect(PalmCivet.byte_size(10.5 * PalmCivet::GIGABYTE)).to eq("10.5G")

expect(PalmCivet.byte_size(100 * PalmCivet::MEGABYTE)).to eq("100M")
expect(PalmCivet.byte_size(100.5 * PalmCivet::MEGABYTE)).to eq("100.5M")

expect(PalmCivet.byte_size(100 * PalmCivet::KILOBYTE)).to eq("100K")
expect(PalmCivet.byte_size(100.5 * PalmCivet::KILOBYTE)).to eq("100.5K")

expect(PalmCivet.byte_size(1)).to eq("1B")
end

it "prints '0' for zero bytes" do
expect(PalmCivet.byte_size(0)).to eq("0")
end

it "raises a type error on non-number values" do
expect {
PalmCivet.byte_size("something else")
}.to raise_error(TypeError, "must be an integer or float")
end
end

it "does something useful" do
expect(false).to eq(true)
describe "#to_bytes" do
it "parses byte amounts with short units (e.g. M, G)" do
expect(PalmCivet.to_bytes("5B")).to eq(5)
expect(PalmCivet.to_bytes("5K")).to eq(5 * PalmCivet::KILOBYTE)
expect(PalmCivet.to_bytes("5M")).to eq(5 * PalmCivet::MEGABYTE)
expect(PalmCivet.to_bytes("5G")).to eq(5 * PalmCivet::GIGABYTE)
expect(PalmCivet.to_bytes("5T")).to eq(5 * PalmCivet::TERABYTE)
end

it "parses byte amounts that are float (e.g. 5.3KB)" do
expect(PalmCivet.to_bytes("13.5KB")).to eq(13824)
expect(PalmCivet.to_bytes("4.5KB")).to eq(4608)
expect(PalmCivet.to_bytes("2.55KB")).to eq(2611)
end

it "parses byte amounts with long units (e.g MB, GB)" do
expect(PalmCivet.to_bytes("5MB")).to eq(5 * PalmCivet::MEGABYTE)
expect(PalmCivet.to_bytes("5mb")).to eq(5 * PalmCivet::MEGABYTE)
expect(PalmCivet.to_bytes("2GB")).to eq(2 * PalmCivet::GIGABYTE)
expect(PalmCivet.to_bytes("3TB")).to eq(3 * PalmCivet::TERABYTE)
end

it "parses byte amounts with long binary units (e.g MiB, GiB)" do
expect(PalmCivet.to_bytes("5MiB")).to eq(5 * PalmCivet::MEGABYTE)
expect(PalmCivet.to_bytes("5mib")).to eq(5 * PalmCivet::MEGABYTE)
expect(PalmCivet.to_bytes("2GiB")).to eq(2 * PalmCivet::GIGABYTE)
expect(PalmCivet.to_bytes("3TiB")).to eq(3 * PalmCivet::TERABYTE)
end

it "allows whitespace before and after the value" do
expect(PalmCivet.to_bytes("\t\n\r 5MB ")).to eq(5 * PalmCivet::MEGABYTE)
end

context "raises an error" do
it "when the unit is missing" do
expect {
PalmCivet.to_bytes("5")
}.to raise_error(PalmCivet::InvalidByteQuantityError)
end

it "when the unit is unrecognized" do
expect {
PalmCivet.to_bytes("5MBB")
}.to raise_error(PalmCivet::InvalidByteQuantityError)

expect {
PalmCivet.to_bytes("5BB")
}.to raise_error(PalmCivet::InvalidByteQuantityError)
end

it "for negative values" do
expect {
PalmCivet.to_bytes("-5MB")
}.to raise_error(PalmCivet::InvalidByteQuantityError)
end

it "for zero values" do
expect {
PalmCivet.to_bytes("0TB")
}.to raise_error(PalmCivet::InvalidByteQuantityError)
end
end
end

describe "#to_megabytes" do
it "parses byte amounts with short units (e.g. M, G)" do
expect(PalmCivet.to_megabytes("5B")).to eq(0)
expect(PalmCivet.to_megabytes("5K")).to eq(0)
expect(PalmCivet.to_megabytes("5M")).to eq(5)
expect(PalmCivet.to_megabytes("5m")).to eq(5)
expect(PalmCivet.to_megabytes("5G")).to eq(5120)
expect(PalmCivet.to_megabytes("5T")).to eq(5242880)
end

it "parses byte amounts with long units (e.g MB, GB)" do
expect(PalmCivet.to_megabytes("5B")).to eq(0)
expect(PalmCivet.to_megabytes("5KB")).to eq(0)
expect(PalmCivet.to_megabytes("5MB")).to eq(5)
expect(PalmCivet.to_megabytes("5mb")).to eq(5)
expect(PalmCivet.to_megabytes("5GB")).to eq(5120)
expect(PalmCivet.to_megabytes("5TB")).to eq(5242880)
end

it "parses byte amounts with long binary units (e.g MiB, GiB)" do
expect(PalmCivet.to_megabytes("5B")).to eq(0)
expect(PalmCivet.to_megabytes("5KiB")).to eq(0)
expect(PalmCivet.to_megabytes("5MiB")).to eq(5)
expect(PalmCivet.to_megabytes("5mib")).to eq(5)
expect(PalmCivet.to_megabytes("5GiB")).to eq(5120)
expect(PalmCivet.to_megabytes("5TiB")).to eq(5242880)
end

it "allows whitespace before and after the value" do
expect(PalmCivet.to_megabytes("\t\n\r 5MB ")).to eq(5)
end

context "raises an error" do
it "when the unit is missing" do
expect {
PalmCivet.to_megabytes("5")
}.to raise_error(PalmCivet::InvalidByteQuantityError)
end

it "when the unit is unrecognized" do
expect {
PalmCivet.to_megabytes("5MBB")
}.to raise_error(PalmCivet::InvalidByteQuantityError)

expect {
PalmCivet.to_megabytes("5BB")
}.to raise_error(PalmCivet::InvalidByteQuantityError)
end

it "for negative values" do
expect {
PalmCivet.to_megabytes("-5MB")
}.to raise_error(PalmCivet::InvalidByteQuantityError)
end

it "for zero values" do
expect {
PalmCivet.to_megabytes("0TB")
}.to raise_error(PalmCivet::InvalidByteQuantityError)
end
end
end
end

0 comments on commit cf33dab

Please sign in to comment.