spec/char_set_spec.rb in chars-0.2.4 vs spec/char_set_spec.rb in chars-0.3.0

- old
+ new

@@ -1,8 +1,10 @@ require 'spec_helper' require 'chars/char_set' +require 'securerandom' + describe Chars::CharSet do let(:integer_range) { (0x41..0x43) } let(:string_range) { ('A'..'Z') } let(:integers) { integer_range.to_a } let(:strings) { string_range.to_a } @@ -89,124 +91,315 @@ describe "#random_byte" do it "should return a random byte" do expect(subject).to include(subject.random_byte) end + + context "when given random: rng" do + let(:rng) { SecureRandom } + + it "must call the #rand method" do + expect(rng).to receive(:rand).with(subject.length).and_return(1) + + subject.random_byte(random: rng) + end + end end describe "#random_char" do it "should return a random char" do expect(subject.include_char?(subject.random_char)).to be(true) end + + context "when given random: rng" do + let(:rng) { SecureRandom } + + it "must call the #rand method" do + expect(rng).to receive(:rand).with(subject.length).and_return(1) + + subject.random_char(random: rng) + end + end end describe "#each_random_byte" do + let(:n) { 10 } + it "should iterate over n random bytes" do - expect(subject.each_random_byte(10).all? { |b| + expect(subject.each_random_byte(n).all? { |b| subject.include?(b) }).to be(true) end + + context "when given random: rng" do + let(:rng) { SecureRandom } + + it "must call the #rand method n times" do + n.times do + expect(rng).to receive(:rand).with(subject.length).and_return(1) + end + + subject.each_random_byte(n, random: rng) { |b| } + end + end end describe "#each_random_char" do + let(:n) { 10 } + it "should iterate over n random chars" do expect(subject.each_random_char(10).all? { |c| subject.include_char?(c) }).to be(true) end + + context "when given random: rng" do + let(:rng) { SecureRandom } + + it "must call the #rand method n times" do + n.times do + expect(rng).to receive(:rand).with(subject.length).and_return(1) + end + + subject.each_random_char(n, random: rng) { |c| } + end + end end describe "#random_bytes" do - it "should return a random Array of bytes" do - random_bytes = subject.random_bytes(10) + context "when given an Integer" do + let(:n) { 10 } - expect(random_bytes.all? { |b| subject.include?(b) }).to be(true) + it "should return a random Array of bytes" do + random_bytes = subject.random_bytes(n) + + expect(random_bytes.all? { |b| subject.include?(b) }).to be(true) + end + + context "when given random: rng" do + let(:rng) { SecureRandom } + + it "must call the #rand method n times" do + n.times do + expect(rng).to receive(:rand).with(subject.length).and_return(1) + end + + subject.random_bytes(n, random: rng) + end + end end - context "with a range of lengths" do + context "when given a Range of lengths" do + let(:lengths) { 5..10 } + it "should return a random Array of bytes with a varying length" do - random_bytes = subject.random_bytes(5..10) + random_bytes = subject.random_bytes(lengths) - expect(random_bytes.length).to be_between(5, 10) + expect(random_bytes.length).to be_between(lengths.begin, lengths.end) expect(random_bytes.all? { |b| subject.include?(b) }).to be(true) end + + context "and when given random: rng" do + let(:rng) { SecureRandom } + + it "must pass random: to Range#sample" do + expect(rng).to receive(:rand).and_return(rand(lengths)).at_least(:once) + + random_bytes = subject.random_bytes(lengths, random: rng) + + expect(random_bytes.length).to be_between(lengths.begin, lengths.end) + end + end end end describe "#random_chars" do - it "should return a random Array of chars" do - random_chars = subject.random_chars(10) + context "when given an Integer" do + let(:n) { 10 } - expect(random_chars.all? { |c| subject.include_char?(c) }).to be(true) + it "should return a random Array of chars" do + random_chars = subject.random_chars(n) + + expect(random_chars.all? { |c| subject.include_char?(c) }).to be(true) + end + + context "when given random: rng" do + let(:rng) { SecureRandom } + + it "must call the #rand method n times" do + n.times do + expect(rng).to receive(:rand).with(subject.length).and_return(rand(n)) + end + + subject.random_chars(n, random: rng) + end + end end - context "with a range of lengths" do + context "when given a Range of lengths" do + let(:lengths) { 5..10 } + it "should return a random Array of chars with a varying length" do - random_chars = subject.random_chars(5..10) + random_chars = subject.random_chars(lengths) - expect(random_chars.length).to be_between(5, 10) + expect(random_chars.length).to be_between(lengths.begin, lengths.end) expect(random_chars.all? { |c| subject.include_char?(c) }).to be(true) end + + context "and when given random: rng" do + let(:rng) { SecureRandom } + + it "must pass random: to Range#sample" do + expect(rng).to receive(:rand).and_return(rand(lengths)).at_least(:once) + + random_chars = subject.random_chars(lengths, random: rng) + + expect(random_chars.length).to be_between(lengths.begin, lengths.end) + end + end end end describe "#random_string" do - it "should return a random String of chars" do - random_string = subject.random_string(10) + context "when given an Integer" do + let(:n) { 10 } - expect(random_string.chars.all? { |b| - subject.include_char?(b) - }).to be(true) + it "should return a random String of chars" do + random_string = subject.random_string(n) + + expect(random_string.chars.all? { |b| + subject.include_char?(b) + }).to be(true) + end + + context "when given random: rng" do + let(:rng) { SecureRandom } + + it "must call the #rand method n times" do + expect(rng).to receive(:rand).with(subject.length).and_return(rand(n)).at_least(:once) + + subject.random_chars(n, random: rng) + end + end end - context "with a range of lengths" do + context "when given a Range of lengths" do + let(:lengths) { 5..10 } + it "should return a random String of chars with a varying length" do - random_string = subject.random_string(5..10) + random_string = subject.random_string(lengths) - expect(random_string.length).to be_between(5, 10) + expect(random_string.length).to be_between(lengths.begin, lengths.end) expect(random_string.chars.all? { |b| subject.include_char?(b) }).to be(true) end + + context "and when given random: rng" do + let(:rng) { SecureRandom } + + it "must pass random: to Range#sample" do + expect(rng).to receive(:rand).and_return(rand(lengths)).at_least(:once) + + random_string = subject.random_string(lengths, random: rng) + + expect(random_string.length).to be_between(lengths.begin, lengths.end) + end + end end end describe "#random_distinct_bytes" do - it "should return a random Array of unique bytes" do - random_bytes = subject.random_distinct_bytes(10) + context "when given an Integer" do + let(:n) { 10 } - expect(random_bytes.uniq).to be == random_bytes - expect(random_bytes.all? { |b| subject.include_byte?(b) }).to be(true) + it "should return a random Array of unique bytes" do + random_bytes = subject.random_distinct_bytes(n) + + expect(random_bytes.length).to eq(n) + expect(random_bytes.uniq).to be == random_bytes + expect(random_bytes.all? { |b| subject.include_byte?(b) }).to be(true) + end + + context "when given random: rng" do + let(:rng) { SecureRandom } + + it "must call the Array#shuffle with random: rng" do + expect_any_instance_of(Array).to receive(:shuffle).with(random: rng).and_return(subject.bytes.shuffle) + + subject.random_distinct_bytes(n, random: rng) + end + end end context "with a Range of lengths" do + let(:lengths) { 5..10 } + it "should return a random Array of unique bytes with a varying length" do - random_bytes = subject.random_distinct_bytes(5..10) + random_bytes = subject.random_distinct_bytes(lengths) expect(random_bytes.uniq).to be == random_bytes - expect(random_bytes.length).to be_between(5, 10) + expect(random_bytes.length).to be_between(lengths.begin, lengths.end) expect(random_bytes.all? { |b| subject.include_byte?(b) }).to be(true) end + + context "and when given random: rng" do + let(:rng) { SecureRandom } + + it "must pass random: to Range#sample" do + expect(rng).to receive(:rand).and_return(rand(lengths)).at_least(:once) + + random_bytes = subject.random_bytes(lengths, random: rng) + + expect(random_bytes.length).to be_between(lengths.begin, lengths.end) + end + end end end describe "#random_distinct_chars" do + let(:n) { 10 } + it "should return a random Array of unique chars" do - random_chars = subject.random_distinct_chars(10) + random_chars = subject.random_distinct_chars(n) expect(random_chars.uniq).to be == random_chars expect(random_chars.all? { |c| subject.include_char?(c) }).to be(true) end - context "with a range of lengths" do + context "when given random: rng" do + let(:rng) { SecureRandom } + + it "must call the Array#shuffle with random: rng" do + expect_any_instance_of(Array).to receive(:shuffle).with(random: rng).and_return(subject.bytes.shuffle(random: rng)) + + subject.random_distinct_bytes(n, random: rng) + end + end + + context "when given a Range of lengths" do + let(:lengths) { 5..10 } + it "should return a random Array of unique chars with a varying length" do - random_chars = subject.random_distinct_chars(5..10) + random_chars = subject.random_distinct_chars(lengths) expect(random_chars.uniq).to be == random_chars - expect(random_chars.length).to be_between(5, 10) + expect(random_chars.length).to be_between(lengths.begin, lengths.end) expect(random_chars.all? { |c| subject.include_char?(c) }).to be(true) end + + context "and when given random: rng" do + let(:rng) { SecureRandom } + + it "must pass random: to Range#sample" do + expect(rng).to receive(:rand).and_return(rand(lengths)).at_least(:once) + + random_bytes = subject.random_bytes(lengths, random: rng) + + expect(random_bytes.length).to be_between(lengths.begin, lengths.end) + end + end end end describe "#==" do it "should be able to be compared with another set of chars" do @@ -230,10 +423,135 @@ expect(sub_set).to be_kind_of(described_class) expect(sub_set).to be_subset(subject) end end + describe "#each_substring_with_index" do + subject { described_class.new(['A', 'B', 'C']) } + + let(:string) { "....AAAA....BBBB....CCCC...." } + + it "must yield each matching substring and index" do + expect { |b| + subject.each_substring_with_index(string,&b) + }.to yield_successive_args( + ["AAAA", string.index("AAAA")], + ["BBBB", string.index("BBBB")], + ["CCCC", string.index("CCCC")] + ) + end + + context "when the string begins with a matching substring" do + let(:string) { "AAAA...." } + + it "must yield the first matching substring" do + expect(subject.each_substring_with_index(string).first).to eq( + ["AAAA", 0] + ) + end + end + + context "when the string ends with a matching substring" do + let(:string) { "AAAA....BBBB....CCCC" } + + it "must yield the last matching substring" do + expect(subject.each_substring_with_index(string).to_a.last).to eq( + ["CCCC", string.rindex("CCCC")] + ) + end + end + + context "when the entire string is a matching substring" do + let(:string) { "AAAAAAAA" } + + it "must yield the entire string" do + expect { |b| + subject.each_substring_with_index(string,&b) + }.to yield_successive_args( [string, 0] ) + end + end + + context "when the matching substrings are shorter than the min_length" do + let(:min_length) { 2 } + + let(:string) { "AA..B...CC.."} + + it "must ignore the substrings shorter than min_length" do + expect { |b| + subject.each_substring_with_index(string, min_length: min_length, &b) + }.to yield_successive_args( + ["AA", string.index("AA")], + ["CC", string.index("CC")] + ) + end + end + + context "when min_length 0" do + let(:min_length) { 0 } + + let(:string) { "A.BB..CCC..."} + + it "must yield all matching substrings, regardless of length" do + expect { |b| + subject.each_substring_with_index(string, min_length: min_length, &b) + }.to yield_successive_args( + ["A", string.index("A")], + ["BB", string.index("BB")], + ["CCC", string.index("CCC")] + ) + end + end + end + + describe "#substrings_with_indexes" do + subject { described_class.new(['A', 'B', 'C']) } + + let(:string) { "....AAAA....BBBB....CCCC...." } + + it "must return the Array of substrings and their indexes" do + expect(subject.substrings_with_indexes(string)).to eq( + [ + ["AAAA", string.index("AAAA")], + ["BBBB", string.index("BBBB")], + ["CCCC", string.index("CCCC")] + ] + ) + end + end + + describe "#each_substring(&block : (String) ->)" do + subject { described_class.new(['A', 'B', 'C']) } + + let(:string) { "....AAAA....BBBB....CCCC...." } + + it "must yield each matching substring" do + expect { |b| + subject.each_substring(string,&b) + }.to yield_successive_args( + "AAAA", + "BBBB", + "CCCC" + ) + end + end + + describe "#substrings" do + subject { described_class.new(['A', 'B', 'C']) } + + let(:string) { "....AAAA....BBBB....CCCC...." } + + it "must return the Array of matching substrings" do + expect(subject.substrings(string)).to eq( + [ + "AAAA", + "BBBB", + "CCCC" + ] + ) + end + end + describe "#strings_in" do subject { described_class.new(['A', 'B', 'C']) } let(:string) { "AAAA....BBBB....CCCC...." } @@ -309,9 +627,75 @@ "CCCC" => string.index("CCCC") } ) end end + end + end + + describe "#each_string" do + let(:length) { 2 } + + let(:expected_strings) do + Chars::StringEnumerator.new(subject,length).to_a + end + + context "when a block is given" do + it "must enumerate through the strings belonging to the character set of the desired length" do + expect { |b| + subject.each_string_of_length(length,&b) + }.to yield_successive_args(*expected_strings) + end + + context "when given a Range of lengths" do + let(:length) { 1..2 } + + let(:expected_strings) do + Chars::StringEnumerator.new(subject,1).to_a + + Chars::StringEnumerator.new(subject,2).to_a + end + + it "must yield strings of lengths in the Range of lengths" do + expect { |b| + subject.each_string_of_length(length,&b) + }.to yield_successive_args(*expected_strings) + end + end + + context "when given an Array of lengths" do + let(:length) { [1,2] } + + let(:expected_strings) do + Chars::StringEnumerator.new(subject,1).to_a + + Chars::StringEnumerator.new(subject,2).to_a + end + + it "must yield strings of lengths in the Range of lengths" do + expect { |b| + subject.each_string_of_length(length,&b) + }.to yield_successive_args(*expected_strings) + end + end + end + + context "when no block is given" do + it "must return an Enumerator" do + expect(subject.each_string_of_length(length)).to be_kind_of(Enumerator) + expect(subject.each_string_of_length(length).to_a).to eq(expected_strings) + end + end + end + + describe "#strings_of_length" do + let(:length) { 2 } + + let(:expected_strings) do + Chars::StringEnumerator.new(subject,length).to_a + end + + it "must return an Enumerator" do + expect(subject.strings_of_length(length)).to be_kind_of(Enumerator) + expect(subject.strings_of_length(length).to_a).to eq(expected_strings) end end describe "#===" do it "should determine if a String is made up of the characters from the char set" do