diff --git a/CHANGELOG.md b/CHANGELOG.md index e7d23ab..08b8d8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,18 +1,52 @@ # Change History for Saropa Dart Utils +## 0.0.11 - Rome (Latest) + +* 🗑️ Removed deprecated functions in ```StringNullableExtensions``` + +* 🐛 Fixed ```StringExtensions.removeStart``` to return the input string when the search param is empty + ```'Hello, World!'.removeStart(''); // 'Hello, World!'``` + +* ⚙️ Added constant ```DateConstants.unixEpochDate``` + ```DateConstants.unixEpochDate; // January 1st, 1970``` + +* ✨ Added function ```DateConstantExtensions.isUnixEpochDate``` + ```DateTime.utc(1970).isUnixEpochDate; // true``` + +* ✨ Added function ```DateConstantExtensions.isUnixEpochDateTime``` + ```DateTime.utc(1970, 1, 1, 0, 0, 1).isUnixEpochDateTime; // false``` + +* ✨ Added function ```IntStringExtensions.ordinal``` + ```101.ordinal(); // 101st``` + +* ✨ Added function ```StringUtils.getNthLatinLetterLower``` + ```String? StringUtils.getNthLatinLetterLower(3) // "c"``` + +* ✨ Added function ```StringUtils.getNthLatinLetterUpper``` + ```String? StringUtils.getNthLatinLetterUpper(4) // "D"``` + +* ✨ Added function ```IntUtils.findGreatestCommonDenominator``` + ```String? IntUtils.findGreatestCommonDenominator(15, 45) // 15``` + +* ✨ Added function ```IntExtensions.countDigits``` + ```(-12345).countDigits() // 5``` + ## 0.0.10 - Paris -* Change start to be nullable ```String? removeStart(String? start)``` +* Change start to be nullable +```String? removeStart(String? start)``` ## 0.0.9 - Geneva * Review of meta data -* Add trimFirst param to ```StringExtensions.removeStart({bool trimFirst = false,}){...}``` +* Add trimFirst param to +```StringExtensions.removeStart({bool trimFirst = false,}){...}``` ## 0.0.8 - Nepal * Review of meta data -* Add trimFirst param to ```StringExtensions.nullIfEmpty({bool trimFirst = true,}){...}``` +* Add trimFirst param to +```StringExtensions.nullIfEmpty({bool trimFirst = true,}){...}``` ## 0.0.7 - Jamaica diff --git a/lib/datetime/date_constant_extensions.dart b/lib/datetime/date_constant_extensions.dart new file mode 100644 index 0000000..a514934 --- /dev/null +++ b/lib/datetime/date_constant_extensions.dart @@ -0,0 +1,40 @@ +import 'package:saropa_dart_utils/datetime/date_constants.dart'; + +/// `DateConstantExtensions` is an extension on the `DateTime` class in Dart. +/// It provides additional properties for performing operations on `DateTime` +/// instances. +/// +/// The `isUnixEpochDate` property checks if the year, month, and day of the +/// `DateTime` instance match those of the Unix epoch date (January 1, 1970). +/// +/// The `isUnixEpochDateTime` property checks if the `DateTime` instance is +/// exactly equal to the Unix epoch date and time (00:00:00 UTC, January 1, +/// 1970). +/// +/// Example usage: +/// ```dart +/// DateTime date = DateTime.utc(1970, 1, 1); +/// bool isEpochDate = date.isUnixEpochDate; // returns true +/// bool isEpochDateTime = date.isUnixEpochDateTime; // returns true +/// ``` +/// +extension DateConstantExtensions on DateTime { + /// Checks if the year, month, and day of the `DateTime` instance + /// match those of the Unix epoch date (January 1, 1970). + /// + /// Returns `true` if the year, month, and day match the Unix epoch date, + /// and `false` otherwise. + /// + bool get isUnixEpochDate => + year == DateConstants.unixEpochDate.year && + month == DateConstants.unixEpochDate.month && + day == DateConstants.unixEpochDate.day; + + /// Checks if the `DateTime` instance is exactly equal to + /// the Unix epoch date and time (00:00:00 UTC, January 1, 1970). + /// + /// Returns `true` if the `DateTime` instance represents the exact + /// Unix epoch date and time, and `false` otherwise. + /// + bool get isUnixEpochDateTime => this == DateConstants.unixEpochDate; +} diff --git a/lib/datetime/date_constants.dart b/lib/datetime/date_constants.dart new file mode 100644 index 0000000..9334ffd --- /dev/null +++ b/lib/datetime/date_constants.dart @@ -0,0 +1,23 @@ +/// `DateConstants` is a utility class in Dart that provides static constants +/// for commonly used dates. This class cannot be instantiated. +/// +/// The `unixEpochDate` constant in this class represents the Unix epoch, +/// which is the date and time that Unix systems use as the reference point +/// for measuring time. The Unix epoch is defined as 00:00:00 Coordinated +/// Universal Time (UTC), Thursday, 1 January 1970. +/// +/// Example usage: +/// ```dart +/// DateTime epoch = DateConstants.unixEpochDate; +/// ``` +/// +class DateConstants { + /// January 1st, 1970 is known as the Unix epoch. It is the date and + /// time that Unix systems use as the reference point for measuring + /// time. This date was chosen arbitrarily by early Unix engineers + /// because they needed a uniform and convenient date for the start + /// of time. + /// + // NOTE: default month and day == 1 + static final DateTime unixEpochDate = DateTime.utc(1970); +} diff --git a/lib/int/int_extensions.dart b/lib/int/int_extensions.dart new file mode 100644 index 0000000..51a7d17 --- /dev/null +++ b/lib/int/int_extensions.dart @@ -0,0 +1,55 @@ +/// `IntExtensions` is an extension on the `int` class in Dart. It provides +/// additional methods for performing operations on integers. +/// +/// The methods in this extension include, but are not limited to, methods for +/// counting the number of digits in an integer. +/// +/// Example usage: +/// ```dart +/// int count = 12345.countDigits(); // returns 5 +/// ``` +/// +/// Note: All methods in this extension are null-safe, meaning they will +/// not throw an exception if the integer on which they are called is null. +/// +extension IntExtensions on int { + /// This function counts the number of digits in an integer. + /// It takes an integer as input and returns the number of digits in the + /// integer. + /// + /// The function handles both positive and negative integers, as well as zero. + /// + /// It uses the method of repeatedly dividing the number by 10 until it + /// becomes 0, + /// + /// which is generally more efficient than converting the number to a string + /// and getting its length. + /// + int countDigits() { + // // Count the number of digits in the absolute value of value + // return value.abs().toString().length; + + // If the number is 0, return 1 + if (this == 0) { + return 1; + } + + // Take the absolute value of the number + var number = abs(); + + // Initialize a counter for the number of digits + var count = 0; + + // Repeat until the number becomes 0 + while (number != 0) { + // Divide the number by 10 + number ~/= 10; + + // Increment the counter + count++; + } + + // Return the count + return count; + } +} diff --git a/lib/int/int_string_extensions.dart b/lib/int/int_string_extensions.dart new file mode 100644 index 0000000..6a23117 --- /dev/null +++ b/lib/int/int_string_extensions.dart @@ -0,0 +1,44 @@ +/// `IntStringExtensions` is an extension on the `int` class in Dart. It +/// provides additional methods for performing operations on integers. +/// +/// The `ordinal` method in this extension returns an ordinal number of +/// `String` type for any integer. +/// +/// It handles both positive and negative integers, as well as zero. +/// +/// Example usage: +/// ```dart +/// int number = 101; +/// String ordinalNumber = number.ordinal(); // returns '101st' +/// ``` +/// +/// Note: All methods in this extension are null-safe, meaning they will not +/// throw an exception if the integer on which they are called is null. +/// +extension IntStringExtensions on int { + /// Returns an ordinal number of `String` type for any integer + /// + /// ```dart + /// 101.ordinal(); // 101st + /// 114.ordinal(); // 101th + /// + /// 999218.ordinal(); // 999218th + /// ``` + /// + /// A [double] typed version can use: value.floor() + /// + String ordinal() { + // all "teens" (12, 13, 14.. 19) are 'th' + if (this >= 11 && this <= 19) { + return '${this}th'; + } + + final num onesPlace = this % 10; + return switch (onesPlace) { + 1 => '${this}st', + 2 => '${this}nd', + 3 => '${this}rd', + _ => '${this}th', + }; + } +} diff --git a/lib/int/int_utils.dart b/lib/int/int_utils.dart new file mode 100644 index 0000000..ad9f125 --- /dev/null +++ b/lib/int/int_utils.dart @@ -0,0 +1,65 @@ +/// `IntUtils` is a utility class in Dart that provides static methods +/// for performing operations on integers. This class cannot be instantiated. +/// +/// The methods in this class include, but are not limited to, methods for +/// finding the greatest common denominator (GCD) of two integers using the +/// Euclidean algorithm. +/// +/// Example usage: +/// ```dart +/// int gcd = IntUtils.findGCD(48, 18); // returns 6 +/// ``` +/// +/// Note: All methods in this class are null-safe, meaning they will not throw +/// an exception if the input integers are not within the expected range. +/// Instead, they will return a reasonable default value (usually null). +/// +class IntUtils { + /// This method finds the greatest common denominator of two integers. + /// It uses the Euclidean algorithm, which is based on the principle that the + /// greatest common denominator of two numbers does not change if the larger + /// number is replaced by its difference with the smaller number. + /// + /// [depth] is used to track the recursion depth, and [maxDepth] is used to + /// prevent the recursion from going too deep. + /// + /// Both [a] and [b] must be non-negative. + /// + static int? findGreatestCommonDenominator( + int a, + int b, { + int depth = 0, + int maxDepth = 500, + }) { + // Both numbers must be non-negative. + if (a < 0 || b < 0) { + return null; + } + + // If the recursion depth exceeds the maximum depth, return -1. + if (depth > maxDepth) { + return null; + } + + // If [a] and [b] are both zero, return null as GCD is undefined. + if (a == 0 && b == 0) { + return null; + } + + // If [b] is 0, then [a] is the greatest common denominator. + if (b == 0) { + return a; + } + + /*** NOTE: RECURSION ***/ + + // Otherwise, recursively call this method with [b] and the remainder of + // [a] divided by [b]. + return findGreatestCommonDenominator( + b, + a % b, + depth: depth + 1, + maxDepth: maxDepth, + ); + } +} diff --git a/lib/string/string_nullable_utils.dart b/lib/string/string_extensions.dart similarity index 58% rename from lib/string/string_nullable_utils.dart rename to lib/string/string_extensions.dart index a892866..82d20db 100644 --- a/lib/string/string_nullable_utils.dart +++ b/lib/string/string_extensions.dart @@ -1,62 +1,63 @@ +import 'package:saropa_dart_utils/string/string_nullable_extensions.dart'; + /// A set of utility methods for working with strings. -extension NullableStringExtensions on String? { +extension StringExtensions on String { /// Returns a new string with the specified [start] removed from the beginning /// of the original string, if it exists. /// + /// NOTE: returns null if empty so it can be used in ?? coalescing + /// /// Example: /// ```dart /// String text = 'www.saropa.com'; /// print(text.removeStart('www.')); // Output: saropa.com /// ``` - @Deprecated('use StringExtensions.removeStart()') - String? removeStart(String start) { - if (start.isEmpty) { + String? removeStart( + String? start, { + bool isCaseSensitive = true, + bool trimFirst = false, + }) { + if (trimFirst) { + // recurse on trimmed + return trim().removeStart( + start, + isCaseSensitive: isCaseSensitive, + ); + } + + if (start.isNullOrEmpty) { return this; } - if (this == null) { - return null; + if (isCaseSensitive) { + return startsWith(start!) ? substring(start.length).nullIfEmpty() : this; } - return this!.startsWith(start) ? this?.substring(start.length) : this; + return toLowerCase().startsWith(start!.toLowerCase()) + ? substring(start.length).nullIfEmpty() + : nullIfEmpty(); } - /// Extension method to check if a [String] is null or empty. - /// - /// Returns `true` if the string is either `null` or an empty string (`""`). - /// Otherwise, returns `false`. - /// - /// Example: - /// ```dart - /// String? text; - /// print(text.isNullOrEmpty); // Output: true - /// - /// text = ""; - /// print(text.isNullOrEmpty); // Output: true - /// - /// text = "Hello"; - /// print(text.isNullOrEmpty); // Output: false - /// ``` - bool get isNullOrEmpty => this == null || this!.isEmpty; + /// Checks if a string is empty. + /// + /// Returns null if the string is empty, otherwise returns the string itself. + String? nullIfEmpty({ + bool trimFirst = true, + }) { + /// If the string is empty, return null. + if (isEmpty) { + return null; + } - /// Extension method to check if a [String] is not null or empty. - /// - /// Returns `true` if the string is neither `null` nor an empty string (`""`). - /// Otherwise, returns `false`. - /// - /// Example: - /// ```dart - /// String? text; - /// print(text.notNullOrEmpty); // Output: false - /// - /// text = ""; - /// print(text.notNullOrEmpty); // Output: false - /// - /// text = "Hello"; - /// print(text.notNullOrEmpty); // Output: true - /// ``` - @Deprecated('use !isNullOrEmpty') - bool get notNullOrEmpty => !isNullOrEmpty; + if (trimFirst) { + final trimmed = trim(); + + return trimmed.isEmpty ? null : trimmed; + } + + /// If the string is not empty, return the string itself. + return this; + } /// Extension method to enclose a [String] in parentheses. /// @@ -77,13 +78,14 @@ extension NullableStringExtensions on String? { /// print(text.encloseInParentheses()); // Output: null /// /// ``` - @Deprecated('use StringExtensions.encloseInParentheses()') String? encloseInParentheses({bool wrapEmpty = false}) { if (isNullOrEmpty) { return wrapEmpty ? '()' : null; } - return '(${this!})'; + // Alternative code: + // return wrapWith(before: '(', after: ')'); + return '($this)'; } /// Extension method to wrap a [String] with a prefix [before] @@ -102,22 +104,12 @@ extension NullableStringExtensions on String? { /// print(text.wrapWith(after: "-Suffix")); // Output: Saropa-Suffix /// ``` /// - @Deprecated('use StringExtensions.wrapWith()') String? wrapWith({String? before, String? after}) { - if (isNullOrEmpty) { + if (isEmpty) { return null; } - String result; - result = this!; - if (!before.isNullOrEmpty) { - result = '$before$result'; - } - if (!after.isNullOrEmpty) { - result = '$result$after'; - } - - return result; + return '${before ?? ""}$this${after ?? ""}'; } /// Extension method to remove consecutive spaces in a [String] @@ -126,21 +118,22 @@ extension NullableStringExtensions on String? { /// If [trim] is true (default), the resulting string will also have leading /// and trailing spaces removed. /// + /// NOTE: returns null if empty so it can be used in ?? coalescing + /// /// Example: /// ```dart /// String text = " Saropa has multiple spaces "; /// print(text.removeConsecutiveSpaces()); // Output: "Saropa has multiple spaces" /// print(text.removeConsecutiveSpaces(trim: false)); // Output: " Saropa has multiple spaces " /// ``` - @Deprecated('use StringExtensions.removeConsecutiveSpaces()') - String removeConsecutiveSpaces({bool trim = true}) { - if (isNullOrEmpty) { - return ''; + String? removeConsecutiveSpaces({bool trim = true}) { + if (isEmpty) { + return null; } String replaced; - replaced = this!.replaceAll(RegExp(r'\s+'), ' '); - return trim ? replaced.trim() : replaced; + replaced = replaceAll(RegExp(r'\s+'), ' '); + return replaced.nullIfEmpty(trimFirst: trim); } /// Extension method to remove consecutive spaces in a [String] @@ -148,14 +141,15 @@ extension NullableStringExtensions on String? { /// /// This is an alias for [removeConsecutiveSpaces]. /// + /// NOTE: returns null if empty so it can be used in ?? coalescing + /// /// Example: /// ```dart /// String text = " Saropa has multiple spaces "; /// print(text.compressSpaces()); // Output: "Saropa has multiple spaces" /// print(text.compressSpaces(trim: false)); // Output: " Saropa has multiple spaces " /// ``` - @Deprecated('use StringExtensions.removeConsecutiveSpaces()') - String compressSpaces({bool trim = true}) { + String? compressSpaces({bool trim = true}) { return removeConsecutiveSpaces(trim: trim); } } diff --git a/lib/string/string_nullable_extensions.dart b/lib/string/string_nullable_extensions.dart new file mode 100644 index 0000000..c354c93 --- /dev/null +++ b/lib/string/string_nullable_extensions.dart @@ -0,0 +1,20 @@ +/// A set of utility methods for working with strings. +extension StringNullableExtensions on String? { + /// Extension method to check if a [String] is null or empty. + /// + /// Returns `true` if the string is either `null` or an empty string (`""`). + /// Otherwise, returns `false`. + /// + /// Example: + /// ```dart + /// String? text; + /// print(text.isNullOrEmpty); // Output: true + /// + /// text = ""; + /// print(text.isNullOrEmpty); // Output: true + /// + /// text = "Hello"; + /// print(text.isNullOrEmpty); // Output: false + /// ``` + bool get isNullOrEmpty => this == null || this!.isEmpty; +} diff --git a/lib/string/string_utils.dart b/lib/string/string_utils.dart index c769e09..59a56f8 100644 --- a/lib/string/string_utils.dart +++ b/lib/string/string_utils.dart @@ -1,155 +1,63 @@ -import 'package:saropa_dart_utils/string/string_nullable_utils.dart'; - -/// A set of utility methods for working with strings. -extension StringExtensions on String { - /// Returns a new string with the specified [start] removed from the beginning - /// of the original string, if it exists. - /// - /// NOTE: returns null if empty so it can be used in ?? coalescing - /// - /// Example: - /// ```dart - /// String text = 'www.saropa.com'; - /// print(text.removeStart('www.')); // Output: saropa.com - /// ``` - String? removeStart( - String? start, { - bool isCaseSensitive = true, - bool trimFirst = false, - }) { - if (trimFirst) { - // recurse on trimmed - return trim().removeStart( - start, - isCaseSensitive: isCaseSensitive, - ); - } - - if (start.isNullOrEmpty) { - return this; - } - - if (isCaseSensitive) { - return startsWith(start!) ? substring(start.length).nullIfEmpty() : this; - } - - return toLowerCase().startsWith(start!.toLowerCase()) - ? substring(start.length).nullIfEmpty() - : nullIfEmpty(); - } - - /// Checks if a string is empty. - /// - /// Returns null if the string is empty, otherwise returns the string itself. - String? nullIfEmpty({ - bool trimFirst = true, - }) { - /// If the string is empty, return null. - if (isEmpty) { +/// `StringUtils` is a utility class in Dart that provides static methods +/// for manipulating and analyzing strings. This class cannot be instantiated. +/// +/// The methods in this class include, but are not limited to, methods for +/// checking string equality, converting strings to different cases, +/// checking if a string is empty or null, and so on. +/// +/// Example usage: +/// ```dart +/// String str = 'Hello, World!'; +/// bool isEmpty = StringUtils.isEmpty(str); // returns false +/// String upper = StringUtils.toUpperCase(str); // returns 'HELLO, WORLD!' +/// ``` +/// +/// Note: All methods in this class are null-safe, meaning they will not throw +/// an exception if the input string is null. Instead, they will return a +/// reasonable default value (usually null or false, depending on the method). +/// +class StringUtils { + /// Returns the n-th letter of the alphabet in uppercase. + /// + /// - [n] is an integer representing the position of the letter in the + /// alphabet (1 = A, 2 = B, etc.). + /// + /// Returns a string containing the n-th letter of the alphabet in uppercase, + /// or `null` if [n] is not within the valid range or an error occurs. + /// + static String? getNthLatinLetterUpper(int n) { + // Check if n is within the valid range. + if (n < 1 || n > 26) { + // If n is not within the valid range, return null. return null; } - if (trimFirst) { - final trimmed = trim(); - - return trimmed.isEmpty ? null : trimmed; - } - - /// If the string is not empty, return the string itself. - return this; - } - - /// Extension method to enclose a [String] in parentheses. - /// - /// If the string is null or empty it returns null unless [wrapEmpty] - /// is set to true, - /// in which case it returns '()'. If an error occurs, it logs the error - /// and returns null. - /// - /// Example: - /// ```dart - /// String? text = "Saropa"; - /// print(text.encloseInParentheses()); // Output: (Saropa) - /// - /// text = ""; - /// print(text.encloseInParentheses(wrapEmpty: true)); // Output: () - /// - /// text = null; - /// print(text.encloseInParentheses()); // Output: null - /// - /// ``` - String? encloseInParentheses({bool wrapEmpty = false}) { - if (isNullOrEmpty) { - return wrapEmpty ? '()' : null; - } - - // Alternative code: - // return wrapWith(before: '(', after: ')'); - return '($this)'; - } - - /// Extension method to wrap a [String] with a prefix [before] - /// and a suffix [after]. - /// - /// If the string is null or empty, it returns null. If [before] - /// or [after] are null or empty, - /// - /// they are ignored in the wrapping process. - /// - /// Examples: - /// ```dart - /// String? text = "Saropa"; - /// print(text.wrapWith(before: "(", after: ")")); // Output: (Saropa) - /// print(text.wrapWith(before: "Prefix-")); // Output: Prefix-Saropa - /// print(text.wrapWith(after: "-Suffix")); // Output: Saropa-Suffix - /// ``` - /// - String? wrapWith({String? before, String? after}) { - if (isEmpty) { - return null; - } + // Calculate the Unicode code point of the n-th letter of the alphabet. + final codePoint = 'A'.codeUnitAt(0) + n - 1; - return '${before ?? ""}$this${after ?? ""}'; + // Create a new string from the Unicode code point and return it. + return String.fromCharCode(codePoint); } - /// Extension method to remove consecutive spaces in a [String] - /// and optionally trim the result. + /// Returns the n-th letter of the alphabet in lowercase. /// - /// If [trim] is true (default), the resulting string will also have leading - /// and trailing spaces removed. + /// - [n] is an integer representing the position of the letter in the + /// alphabet (1 = a, 2 = b, etc.). /// - /// NOTE: returns null if empty so it can be used in ?? coalescing + /// Returns a string containing the n-th letter of the alphabet in lowercase, + /// or `null` if [n] is not within the valid range or an error occurs. /// - /// Example: - /// ```dart - /// String text = " Saropa has multiple spaces "; - /// print(text.removeConsecutiveSpaces()); // Output: "Saropa has multiple spaces" - /// print(text.removeConsecutiveSpaces(trim: false)); // Output: " Saropa has multiple spaces " - /// ``` - String? removeConsecutiveSpaces({bool trim = true}) { - if (isEmpty) { + static String? getNthLatinLetterLower(int n) { + // Check if n is within the valid range. + if (n < 1 || n > 26) { + // If n is not within the valid range, return null. return null; } - String replaced; - replaced = replaceAll(RegExp(r'\s+'), ' '); - return replaced.nullIfEmpty(trimFirst: trim); - } + // Calculate the Unicode code point of the n-th letter of the alphabet. + final codePoint = 'a'.codeUnitAt(0) + n - 1; - /// Extension method to remove consecutive spaces in a [String] - /// and optionally trim the result. - /// - /// This is an alias for [removeConsecutiveSpaces]. - /// - /// NOTE: returns null if empty so it can be used in ?? coalescing - /// - /// Example: - /// ```dart - /// String text = " Saropa has multiple spaces "; - /// print(text.compressSpaces()); // Output: "Saropa has multiple spaces" - /// print(text.compressSpaces(trim: false)); // Output: " Saropa has multiple spaces " - /// ``` - String? compressSpaces({bool trim = true}) { - return removeConsecutiveSpaces(trim: trim); + // Create a new string from the Unicode code point and return it. + return String.fromCharCode(codePoint); } } diff --git a/pubspec.yaml b/pubspec.yaml index 8d4ab59..ec63dc3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: saropa_dart_utils description: "Boilerplate reduction tools and human readable extension methods by Saropa" -version: 0.0.10+Paris +version: 0.0.11+Rome homepage: https://app.saropa.com repository: https://github.com/saropa/saropa_dart_utils @@ -26,7 +26,7 @@ dev_dependencies: # This package provides lint rules for Dart and Flutter which are used at Very Good Ventures. For more information, see the complete list of options. # https://pub.dev/packages/very_good_analysis # https://pub.dev/packages/very_good_analysis/changelog - very_good_analysis: ^5.1.0 + very_good_analysis: ^6.0.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/test/datetime/date_constant_extensions.dart b/test/datetime/date_constant_extensions.dart new file mode 100644 index 0000000..af86802 --- /dev/null +++ b/test/datetime/date_constant_extensions.dart @@ -0,0 +1,33 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:saropa_dart_utils/datetime/date_constant_extensions.dart'; + +void main() { + group('isUnixEpochDate', () { + test('returns true when the date is the Unix epoch date', () { + expect(DateTime.utc(1970).isUnixEpochDate, isTrue); + }); + + test('returns false when the date is not the Unix epoch date', () { + expect(DateTime.utc(1970, 1, 2).isUnixEpochDate, isFalse); + expect(DateTime.utc(1969, 12, 31).isUnixEpochDate, isFalse); + expect(DateTime.utc(1970, 2).isUnixEpochDate, isFalse); + expect(DateTime.utc(1969).isUnixEpochDate, isFalse); + }); + }); + + group('isUnixEpochDateTime', () { + test('returns true when the date and time are the Unix epoch', () { + expect(DateTime.utc(1970).isUnixEpochDateTime, isTrue); + }); + + test('returns false when the date and time are not the Unix epoch', () { + expect(DateTime.utc(1970, 1, 1, 0, 0, 1).isUnixEpochDateTime, isFalse); + expect(DateTime.utc(1970, 1, 1, 0, 1).isUnixEpochDateTime, isFalse); + expect(DateTime.utc(1970, 1, 1, 1).isUnixEpochDateTime, isFalse); + expect( + DateTime.utc(1969, 12, 31, 23, 59, 59).isUnixEpochDateTime, + isFalse, + ); + }); + }); +} diff --git a/test/datetime/date_constants_test.dart b/test/datetime/date_constants_test.dart new file mode 100644 index 0000000..820fbba --- /dev/null +++ b/test/datetime/date_constants_test.dart @@ -0,0 +1,46 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:saropa_dart_utils/datetime/date_constants.dart'; + +void main() { + group('unixEpochDate', () { + test('returns the correct Unix epoch date', () { + expect(DateConstants.unixEpochDate, equals(DateTime.utc(1970))); + }); + + test('returns a date with year 1970', () { + expect(DateConstants.unixEpochDate.year, equals(1970)); + }); + + test('returns a date with month 1', () { + expect(DateConstants.unixEpochDate.month, equals(1)); + }); + + test('returns a date with day 1', () { + expect(DateConstants.unixEpochDate.day, equals(1)); + }); + + test('returns a date with hour 0', () { + expect(DateConstants.unixEpochDate.hour, equals(0)); + }); + + test('returns a date with minute 0', () { + expect(DateConstants.unixEpochDate.minute, equals(0)); + }); + + test('returns a date with second 0', () { + expect(DateConstants.unixEpochDate.second, equals(0)); + }); + + test('returns a date with millisecond 0', () { + expect(DateConstants.unixEpochDate.millisecond, equals(0)); + }); + + test('returns a date with microsecond 0', () { + expect(DateConstants.unixEpochDate.microsecond, equals(0)); + }); + + test('returns a date with timezone offset of 0', () { + expect(DateConstants.unixEpochDate.timeZoneOffset, equals(Duration.zero)); + }); + }); +} diff --git a/test/int/int_extensions_test.dart b/test/int/int_extensions_test.dart new file mode 100644 index 0000000..a42eed8 --- /dev/null +++ b/test/int/int_extensions_test.dart @@ -0,0 +1,36 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:saropa_dart_utils/int/int_utils.dart'; + +void main() { + group('findGreatestCommonDenominator', () { + test('returns null when a or b is negative', () { + expect(IntUtils.findGreatestCommonDenominator(-1, 1), isNull); + expect(IntUtils.findGreatestCommonDenominator(1, -1), isNull); + }); + + test('returns null when a and b are both zero', () { + expect(IntUtils.findGreatestCommonDenominator(0, 0), isNull); + }); + + test('returns the non-zero number when one of the numbers is zero', () { + expect(IntUtils.findGreatestCommonDenominator(0, 5), equals(5)); + expect(IntUtils.findGreatestCommonDenominator(7, 0), equals(7)); + }); + + test('returns 1 when a and b are co-prime', () { + expect(IntUtils.findGreatestCommonDenominator(13, 7), equals(1)); + }); + + test( + 'returns the common factor when a and b are multiples of ' + 'a common number', () { + expect(IntUtils.findGreatestCommonDenominator(15, 45), equals(15)); + }); + + test('returns a when a equals b', () { + expect(IntUtils.findGreatestCommonDenominator(9, 9), equals(9)); + }); + + // Add more test cases here... + }); +} diff --git a/test/int/int_string_extensions_test.dart b/test/int/int_string_extensions_test.dart new file mode 100644 index 0000000..2e7e4fa --- /dev/null +++ b/test/int/int_string_extensions_test.dart @@ -0,0 +1,46 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:saropa_dart_utils/int/int_string_extensions.dart'; + +void main() { + group('ordinal', () { + test('returns "1st" when the number is 1', () { + expect(1.ordinal(), equals('1st')); + }); + + test('returns "2nd" when the number is 2', () { + expect(2.ordinal(), equals('2nd')); + }); + + test('returns "3rd" when the number is 3', () { + expect(3.ordinal(), equals('3rd')); + }); + + test('returns "4th" when the number is 4', () { + expect(4.ordinal(), equals('4th')); + }); + + test('returns "11th" when the number is 11', () { + expect(11.ordinal(), equals('11th')); + }); + + test('returns "12th" when the number is 12', () { + expect(12.ordinal(), equals('12th')); + }); + + test('returns "13th" when the number is 13', () { + expect(13.ordinal(), equals('13th')); + }); + + test('returns "21st" when the number is 21', () { + expect(21.ordinal(), equals('21st')); + }); + + test('returns "22nd" when the number is 22', () { + expect(22.ordinal(), equals('22nd')); + }); + + test('returns "23rd" when the number is 23', () { + expect(23.ordinal(), equals('23rd')); + }); + }); +} diff --git a/test/int/int_utils_test.dart b/test/int/int_utils_test.dart new file mode 100644 index 0000000..1c0790e --- /dev/null +++ b/test/int/int_utils_test.dart @@ -0,0 +1,29 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:saropa_dart_utils/int/int_extensions.dart'; + +void main() { + group('countDigits', () { + test('returns 1 when the number is 0', () { + expect(0.countDigits(), equals(1)); + }); + + test('returns the correct number of digits for positive numbers', () { + expect(123.countDigits(), equals(3)); + expect(1234.countDigits(), equals(4)); + expect(12345.countDigits(), equals(5)); + }); + + test('returns the correct number of digits for negative numbers', () { + expect((-123).countDigits(), equals(3)); + expect((-1234).countDigits(), equals(4)); + expect((-12345).countDigits(), equals(5)); + }); + + test('returns the correct number of digits for numbers with leading zeros', + () { + expect(00123.countDigits(), equals(3)); + }); + + // Add more test cases here... + }); +} diff --git a/test/string/string_extensions_test.dart b/test/string/string_extensions_test.dart new file mode 100644 index 0000000..ad69ac4 --- /dev/null +++ b/test/string/string_extensions_test.dart @@ -0,0 +1,176 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:saropa_dart_utils/string/string_extensions.dart'; + +void main() { + group('nullIfEmpty', () { + test('returns null when string is empty', () { + expect(''.nullIfEmpty(), isNull); + }); + + test('returns null when string contains only spaces and trimFirst is true', + () { + expect(' '.nullIfEmpty(), isNull); + }); + + test( + 'returns string itself when string contains only spaces and trimFirst ' + 'is false', () { + expect(' '.nullIfEmpty(trimFirst: false), equals(' ')); + }); + + test('returns string itself when string is not empty', () { + expect('Hello'.nullIfEmpty(), equals('Hello')); + }); + + test( + 'returns trimmed string when string has leading/trailing spaces and trimFirst is true', + () { + expect(' Hello '.nullIfEmpty(), equals('Hello')); + }); + }); + + group('removeStart', () { + test('returns input string when start string is empty', () { + final result = 'Hello, World!'.removeStart(''); + expect(result, 'Hello, World!'); + }); + + test( + 'returns original string when start string is not a prefix ' + '(case sensitive)', () { + final result = 'Hello, World!'.removeStart('hello'); + expect(result, equals('Hello, World!')); + }); + + test( + 'returns string without start string when start string is a prefix ' + '(case sensitive)', () { + final result = 'Hello, World!'.removeStart('Hello'); + expect(result, equals(', World!')); + }); + + test( + 'returns original string when start string is not a prefix ' + '(case insensitive)', () { + final result = + 'Hello, World!'.removeStart('WORLD', isCaseSensitive: false); + expect(result, equals('Hello, World!')); + }); + + test( + 'returns string without start string when start string is a prefix ' + '(case insensitive)', () { + final result = + 'Hello, World!'.removeStart('HELLO', isCaseSensitive: false); + expect(result, equals(', World!')); + }); + + test('When string is empty', () { + expect(''.removeStart('Hello'), equals('')); + }); + + test('When find is empty', () { + expect('Hello'.removeStart(''), equals('Hello')); + }); + + test('When string starts with find', () { + expect('Hello'.removeStart('He'), equals('llo')); + }); + + test('When string does not start with find', () { + expect('Hello'.removeStart('lo'), equals('Hello')); + }); + + test('When trimFirst is true and string starts with find', () { + expect(' Hello'.removeStart('Hello', trimFirst: true), equals(null)); + }); + + test('When trimFirst is true and string does not start with find', () { + expect(' Hello'.removeStart('lo', trimFirst: true), equals('Hello')); + }); + }); + + group('removeConsecutiveSpaces', () { + test('returns empty string when input string is null or empty', () { + final result = ''.removeConsecutiveSpaces(); + expect(result, equals(null)); + }); + + test('returns string with consecutive spaces removed and trimmed', () { + final result = ' Hello, World! '.removeConsecutiveSpaces(); + expect(result, equals('Hello, World!')); + }); + + test('returns string with consecutive spaces removed and not trimmed', () { + final result = ' Hello, World! '.removeConsecutiveSpaces(trim: false); + expect(result, equals(' Hello, World! ')); + }); + }); + + group('compressSpaces', () { + test('returns empty string when input string is null or empty', () { + final result = ''.compressSpaces(); + expect(result, equals(null)); + }); + + test('returns string with consecutive spaces removed and trimmed', () { + final result = ' Hello, World! '.compressSpaces(); + expect(result, equals('Hello, World!')); + }); + + test('returns string with consecutive spaces removed and not trimmed', () { + final result = ' Hello, World! '.compressSpaces(trim: false); + expect(result, equals(' Hello, World! ')); + }); + }); + + group('wrapWith', () { + test('returns null when input string is empty', () { + final result = ''.wrapWith(before: 'Hello', after: 'World'); + expect(result, isNull); + }); + + test('returns original string when before and after are null', () { + final result = 'Hello, World!'.wrapWith(); + expect(result, equals('Hello, World!')); + }); + + test('returns string wrapped with before and after when they are not null', + () { + final result = + 'Hello, World!'.wrapWith(before: 'Start: ', after: ' :End'); + expect(result, equals('Start: Hello, World! :End')); + }); + + test('returns string wrapped with before when after is null', () { + final result = 'Hello, World!'.wrapWith(before: 'Start: '); + expect(result, equals('Start: Hello, World!')); + }); + + test('returns string wrapped with after when before is null', () { + final result = 'Hello, World!'.wrapWith(after: ' :End'); + expect(result, equals('Hello, World! :End')); + }); + }); + + group('encloseInParentheses', () { + test('returns null when input string is empty and wrapEmpty is false', () { + final result = ''.encloseInParentheses(); + expect(result, isNull); + }); + + test( + 'returns empty parentheses when input string is empty and ' + 'wrapEmpty is true', () { + final result = ''.encloseInParentheses(wrapEmpty: true); + expect(result, equals('()')); + }); + + test( + 'returns string enclosed in parentheses when input string is not empty', + () { + final result = 'Hello, World!'.encloseInParentheses(); + expect(result, equals('(Hello, World!)')); + }); + }); +} diff --git a/test/string/string_nullable_utils_test.dart b/test/string/string_nullable_extensions_test.dart similarity index 80% rename from test/string/string_nullable_utils_test.dart rename to test/string/string_nullable_extensions_test.dart index 23d17b4..43614d5 100644 --- a/test/string/string_nullable_utils_test.dart +++ b/test/string/string_nullable_extensions_test.dart @@ -1,5 +1,5 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:saropa_dart_utils/string/string_nullable_utils.dart'; +import 'package:saropa_dart_utils/string/string_nullable_extensions.dart'; // import 'package:test/test.dart'; void main() { diff --git a/test/string/string_utils_test.dart b/test/string/string_utils_test.dart index 3c3c3ce..e9ab238 100644 --- a/test/string/string_utils_test.dart +++ b/test/string/string_utils_test.dart @@ -2,175 +2,33 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:saropa_dart_utils/string/string_utils.dart'; void main() { - group('nullIfEmpty', () { - test('returns null when string is empty', () { - expect(''.nullIfEmpty(), isNull); + group('getNthLatinLetterUpper', () { + test('returns null when n is out of range', () { + expect(StringUtils.getNthLatinLetterUpper(0), isNull); + expect(StringUtils.getNthLatinLetterUpper(27), isNull); }); - test('returns null when string contains only spaces and trimFirst is true', - () { - expect(' '.nullIfEmpty(), isNull); + test('returns "A" when n is 1', () { + expect(StringUtils.getNthLatinLetterUpper(1), equals('A')); }); - test( - 'returns string itself when string contains only spaces and trimFirst ' - 'is false', () { - expect(' '.nullIfEmpty(trimFirst: false), equals(' ')); - }); - - test('returns string itself when string is not empty', () { - expect('Hello'.nullIfEmpty(), equals('Hello')); - }); - - test( - 'returns trimmed string when string has leading/trailing spaces and trimFirst is true', - () { - expect(' Hello '.nullIfEmpty(), equals('Hello')); - }); - }); - - group('removeStart', () { - test('returns null when start string is empty', () { - final result = 'Hello, World!'.removeStart(''); - expect(result, isNull); - }); - - test( - 'returns original string when start string is not a prefix ' - '(case sensitive)', () { - final result = 'Hello, World!'.removeStart('hello'); - expect(result, equals('Hello, World!')); - }); - - test( - 'returns string without start string when start string is a prefix ' - '(case sensitive)', () { - final result = 'Hello, World!'.removeStart('Hello'); - expect(result, equals(', World!')); - }); - - test( - 'returns original string when start string is not a prefix ' - '(case insensitive)', () { - final result = - 'Hello, World!'.removeStart('WORLD', isCaseSensitive: false); - expect(result, equals('Hello, World!')); - }); - - test( - 'returns string without start string when start string is a prefix ' - '(case insensitive)', () { - final result = - 'Hello, World!'.removeStart('HELLO', isCaseSensitive: false); - expect(result, equals(', World!')); - }); - - test('When string is empty', () { - expect(''.removeStart('Hello'), equals('')); - }); - - test('When find is empty', () { - expect('Hello'.removeStart(''), equals('Hello')); - }); - - test('When string starts with find', () { - expect('Hello'.removeStart('He'), equals('llo')); - }); - - test('When string does not start with find', () { - expect('Hello'.removeStart('lo'), equals('Hello')); - }); - - test('When trimFirst is true and string starts with find', () { - expect(' Hello'.removeStart('Hello', trimFirst: true), equals(null)); - }); - - test('When trimFirst is true and string does not start with find', () { - expect(' Hello'.removeStart('lo', trimFirst: true), equals('Hello')); - }); - }); - - group('removeConsecutiveSpaces', () { - test('returns empty string when input string is null or empty', () { - final result = ''.removeConsecutiveSpaces(); - expect(result, equals(null)); - }); - - test('returns string with consecutive spaces removed and trimmed', () { - final result = ' Hello, World! '.removeConsecutiveSpaces(); - expect(result, equals('Hello, World!')); - }); - - test('returns string with consecutive spaces removed and not trimmed', () { - final result = ' Hello, World! '.removeConsecutiveSpaces(trim: false); - expect(result, equals(' Hello, World! ')); - }); - }); - - group('compressSpaces', () { - test('returns empty string when input string is null or empty', () { - final result = ''.compressSpaces(); - expect(result, equals(null)); - }); - - test('returns string with consecutive spaces removed and trimmed', () { - final result = ' Hello, World! '.compressSpaces(); - expect(result, equals('Hello, World!')); - }); - - test('returns string with consecutive spaces removed and not trimmed', () { - final result = ' Hello, World! '.compressSpaces(trim: false); - expect(result, equals(' Hello, World! ')); - }); - }); - - group('wrapWith', () { - test('returns null when input string is empty', () { - final result = ''.wrapWith(before: 'Hello', after: 'World'); - expect(result, isNull); - }); - - test('returns original string when before and after are null', () { - final result = 'Hello, World!'.wrapWith(); - expect(result, equals('Hello, World!')); - }); - - test('returns string wrapped with before and after when they are not null', - () { - final result = - 'Hello, World!'.wrapWith(before: 'Start: ', after: ' :End'); - expect(result, equals('Start: Hello, World! :End')); - }); - - test('returns string wrapped with before when after is null', () { - final result = 'Hello, World!'.wrapWith(before: 'Start: '); - expect(result, equals('Start: Hello, World!')); - }); - - test('returns string wrapped with after when before is null', () { - final result = 'Hello, World!'.wrapWith(after: ' :End'); - expect(result, equals('Hello, World! :End')); + test('returns "Z" when n is 26', () { + expect(StringUtils.getNthLatinLetterUpper(26), equals('Z')); }); }); - group('encloseInParentheses', () { - test('returns null when input string is empty and wrapEmpty is false', () { - final result = ''.encloseInParentheses(); - expect(result, isNull); + group('getNthLatinLetterLower', () { + test('returns null when n is out of range', () { + expect(StringUtils.getNthLatinLetterLower(0), isNull); + expect(StringUtils.getNthLatinLetterLower(27), isNull); }); - test( - 'returns empty parentheses when input string is empty and ' - 'wrapEmpty is true', () { - final result = ''.encloseInParentheses(wrapEmpty: true); - expect(result, equals('()')); + test('returns "a" when n is 1', () { + expect(StringUtils.getNthLatinLetterLower(1), equals('a')); }); - test( - 'returns string enclosed in parentheses when input string is not empty', - () { - final result = 'Hello, World!'.encloseInParentheses(); - expect(result, equals('(Hello, World!)')); + test('returns "z" when n is 26', () { + expect(StringUtils.getNthLatinLetterLower(26), equals('z')); }); }); }