Skip to content

Commit

Permalink
feat: Added nanoId support (#973)
Browse files Browse the repository at this point in the history
* generate nano id

* tests

* done

* changed function name

* split tests
  • Loading branch information
KatkaMarcincakova authored Nov 5, 2024
1 parent 716b6be commit 5a47de7
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 1 deletion.
53 changes: 52 additions & 1 deletion include/faker-cxx/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -299,4 +299,55 @@ FAKER_CXX_EXPORT std::string numeric(unsigned length = 1, bool allowLeadingZeros
* @endcode
*/
FAKER_CXX_EXPORT std::string numeric(GuaranteeMap&& guarantee, unsigned length = 1, bool allowLeadingZeros = true);
}

/**
* @brief Generates a unique, URL-safe string identifier of the specified length.
*
* This function generates a unique identifier using a cryptographically secure
* random number generator, with the output length set by the `length` parameter.
*
* @param length The exact length of the identifier to generate.
*
* @returns A unique, URL-safe string identifier of the specified length.
*
* @code
* nanoId(10); // Possible output: "F8aXz1Q4wB"
* nanoId(21); // Possible output: "V2JlO7GZ1kPl9FxErRqzS"
* @endcode
*/
FAKER_CXX_EXPORT std::string nanoId(int length);

/**
* @brief Generates a unique, URL-safe string identifier of default length.
*
* This function generates a unique identifier with a default length of 10 characters.
* The identifier is URL-safe and created using a cryptographically secure
* random number generator.
*
* @returns A unique, URL-safe string identifier of default length (10 characters).
*
* @code
* nanoId(); // Possible output: "Hf5lN8L2wQ"
* @endcode
*/
FAKER_CXX_EXPORT std::string nanoId();

/**
* @brief Generates a unique, URL-safe string identifier of random length within a specified range.
*
* This function generates a unique identifier with a length that varies between
* `minLength` and `maxLength`, inclusive. The identifier is URL-safe and created
* using a cryptographically secure random number generator.
*
* @param minLength The minimum length of the identifier.
* @param maxLength The maximum length of the identifier.
*
* @returns A unique, URL-safe string identifier with a length between `minLength` and `maxLength`.
*
* @code
* nanoId(10, 15); // Possible output: "Vb2Ej8G9wPcQ2"
* nanoId(5, 8); // Possible output: "P1zZ3x"
* @endcode
*/
FAKER_CXX_EXPORT std::string nanoId(int minLength, int maxLength);
}
59 changes: 59 additions & 0 deletions src/modules/string.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <cassert>
#include <map>
#include <random>
#include <set>
#include <stdexcept>
#include <string>
Expand Down Expand Up @@ -300,4 +301,62 @@ std::string numeric(GuaranteeMap&& guarantee, unsigned length, bool allowLeading
return firstChar + generateStringWithGuarantee(guarantee, targetCharacters, length - 1);
}
}

std::string nanoId(int length)
{

if (length < 1)
return "";

std::random_device rd;
std::mt19937 generator(rd());
std::uniform_int_distribution<int> distribution(0, nanoIdAllowedCharacters.size() - 1);

std::string id;
for (size_t i = 0; i < length; ++i)
{
id += nanoIdAllowedCharacters[distribution(generator)];
}

return id;
}

std::string nanoId()
{
std::random_device rd;
std::mt19937 generator(rd());
std::uniform_int_distribution<int> distribution(0, nanoIdAllowedCharacters.size() - 1);

std::string id;
for (size_t i = 0; i < 10; ++i)
{
id += nanoIdAllowedCharacters[distribution(generator)];
}

return id;
}

std::string nanoId(int minLength, int maxLength)
{
if (maxLength - minLength < 1)
return "";

std::random_device rd;
std::mt19937 generator(rd());

std::uniform_int_distribution<int> lengthDistribution(minLength, maxLength);
int length = lengthDistribution(generator);

std::uniform_int_distribution<int> charDistribution(0, nanoIdAllowedCharacters.size() - 1);

std::string id;
for (size_t i = 0; i < length; ++i)
{
id += nanoIdAllowedCharacters[charDistribution(generator)];
}

return id;
}


}
1 change: 1 addition & 0 deletions src/modules/string_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const std::string lowerAlphanumericCharacters{lowerCharacters + numericCharacter
const std::string upperAlphanumericCharacters{upperCharacters + numericCharacters};
const std::string mixedAlphanumericCharacters{upperCharacters + lowerCharacters + numericCharacters};
const std::string symbolCharacters{"~`!@#$%^&*()_-+={[}]|:;\"'<,>.?/"};
const std::string nanoIdAllowedCharacters{mixedAlphanumericCharacters + "_-"};

const std::set<char> lowerCharSet{
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
Expand Down
21 changes: 21 additions & 0 deletions tests/modules/string_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -923,3 +923,24 @@ TEST_F(StringTest, invalidGuaranteeForNumeric4)
GuaranteeMap guarantee = {{'0', {5}}};
ASSERT_THROW(numeric(std::move(guarantee), numericLength, false), std::invalid_argument);
}

TEST_F(StringTest, shouldGenerateNanoIdWithSpecificLength)
{
ASSERT_EQ(nanoId(20).size(), 20);
ASSERT_EQ(nanoId(0).size(), 0);
ASSERT_EQ(nanoId(-1).size(), 0);
}

TEST_F(StringTest, shouldGenerateNanoIdWithDefaultLength)
{
ASSERT_EQ(nanoId().size(), 10);
}

TEST_F(StringTest, shouldGenerateNanoIdWithLengthFromRange)
{
ASSERT_EQ(nanoId(8, 2).size(), 0);

const auto rangeNanoid = nanoId(2, 8);
ASSERT_GE(rangeNanoid.size(), 2);
ASSERT_LE(rangeNanoid.size(), 8);
}

0 comments on commit 5a47de7

Please sign in to comment.