diff --git a/CapyKit/CapyKit.sln b/CapyKit/CapyKit.sln
index a9c487d..e9b8870 100644
--- a/CapyKit/CapyKit.sln
+++ b/CapyKit/CapyKit.sln
@@ -12,6 +12,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{7CF6DF6D-3B04-46F8-A40B-537D21BCA0B4}") = "Documentation", "..\Documentation\Documentation.shfbproj", "{E23D3844-E594-487E-979B-2D35B1B9AAE8}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "..\Tests\Tests.csproj", "{D142EF3D-8F61-40B6-8358-7D5B7F8A2B18}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -26,6 +28,10 @@ Global
{E23D3844-E594-487E-979B-2D35B1B9AAE8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E23D3844-E594-487E-979B-2D35B1B9AAE8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E23D3844-E594-487E-979B-2D35B1B9AAE8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D142EF3D-8F61-40B6-8358-7D5B7F8A2B18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D142EF3D-8F61-40B6-8358-7D5B7F8A2B18}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D142EF3D-8F61-40B6-8358-7D5B7F8A2B18}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D142EF3D-8F61-40B6-8358-7D5B7F8A2B18}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/CapyKit/Password.cs b/CapyKit/Password.cs
index 179413d..5b02b7e 100644
--- a/CapyKit/Password.cs
+++ b/CapyKit/Password.cs
@@ -47,7 +47,7 @@ namespace CapyKit
{
return pbkdf2Algorithm.Value;
}
- }
+ }
#endregion
@@ -58,7 +58,7 @@ namespace CapyKit
/// The salt used for encryption.
/// The algorithm used for password encryption.
/// A variable-length parameters list containing arguments to include for the .
- internal Password(string password, byte[] salt, IPasswordAlgorithm algorithm, params object[] args)
+ public Password(string password, byte[] salt, IPasswordAlgorithm algorithm, params object[] args)
{
// We know there will always be a salt, so we can prepend it to h
var augmented = args.Prepend(salt).ToArray();
@@ -85,8 +85,8 @@ namespace CapyKit
}
return this.Algorithm.AlgorithmName == objPassword.Algorithm.AlgorithmName
- && this.Hash == objPassword.Hash
- && this.Salt == objPassword.Salt;
+ && this.Hash.SequenceEqual(objPassword.Hash)
+ && this.Salt.SequenceEqual(objPassword.Salt);
}
///
diff --git a/Documentation/Help/F_Tests_StringExtensions_Replacement.md b/Documentation/Help/F_Tests_StringExtensions_Replacement.md
new file mode 100644
index 0000000..940c109
--- /dev/null
+++ b/Documentation/Help/F_Tests_StringExtensions_Replacement.md
@@ -0,0 +1,31 @@
+# Replacement Field
+
+
+\[Missing <summary> documentation for "F:Tests.StringExtensions.Replacement"\]
+
+
+
+## Definition
+**Namespace:** Tests
+**Assembly:** Tests (in Tests.exe) Version: 1.0.0
+
+**C#**
+``` C#
+private const string Replacement = "Replaced"
+```
+**F#**
+``` F#
+static val mutable private Replacement: string
+```
+
+
+
+#### Field Value
+String
+
+## See Also
+
+
+#### Reference
+StringExtensions Class
+Tests Namespace
diff --git a/Documentation/Help/Fields_T_Tests_StringExtensions.md b/Documentation/Help/Fields_T_Tests_StringExtensions.md
new file mode 100644
index 0000000..9bb583a
--- /dev/null
+++ b/Documentation/Help/Fields_T_Tests_StringExtensions.md
@@ -0,0 +1,18 @@
+# StringExtensions Fields
+
+
+
+
+## Fields
+
+
+## See Also
+
+
+#### Reference
+StringExtensions Class
+Tests Namespace
diff --git a/Documentation/Help/M_CapyKit_Password__ctor.md b/Documentation/Help/M_CapyKit_Password__ctor.md
index 051937c..ba77be7 100644
--- a/Documentation/Help/M_CapyKit_Password__ctor.md
+++ b/Documentation/Help/M_CapyKit_Password__ctor.md
@@ -11,7 +11,7 @@ Constructor.
**C#**
``` C#
-internal Password(
+public Password(
string password,
byte[] salt,
IPasswordAlgorithm algorithm,
diff --git a/Documentation/Help/M_Tests_Passwords_PasswordTests_GenerateSalt.md b/Documentation/Help/M_Tests_Passwords_PasswordTests_GenerateSalt.md
new file mode 100644
index 0000000..dd14d06
--- /dev/null
+++ b/Documentation/Help/M_Tests_Passwords_PasswordTests_GenerateSalt.md
@@ -0,0 +1,42 @@
+# GenerateSalt Method
+
+
+\[Missing <summary> documentation for "M:Tests.Passwords.PasswordTests.GenerateSalt(System.Int32)"\]
+
+
+
+## Definition
+**Namespace:** Tests
+**Assembly:** Tests (in Tests.exe) Version: 1.0.0
+
+**C#**
+``` C#
+private static byte[] GenerateSalt(
+ int size = 16
+)
+```
+**F#**
+``` F#
+private static member GenerateSalt :
+ ?size : int
+(* Defaults:
+ let _size = defaultArg size 16
+*)
+-> byte[]
+```
+
+
+
+#### Parameters
+- Int32 (Optional)
- \[Missing <param name="size"/> documentation for "M:Tests.Passwords.PasswordTests.GenerateSalt(System.Int32)"\]
+
+#### Return Value
+Byte[]
+\[Missing <returns> documentation for "M:Tests.Passwords.PasswordTests.GenerateSalt(System.Int32)"\]
+
+## See Also
+
+
+#### Reference
+Passwords.PasswordTests Class
+Tests Namespace
diff --git a/Documentation/Help/M_Tests_Passwords_PasswordTests_PasswordCreation_WithInvalidSalt_ReturnsEmptyHash.md b/Documentation/Help/M_Tests_Passwords_PasswordTests_PasswordCreation_WithInvalidSalt_ReturnsEmptyHash.md
new file mode 100644
index 0000000..19b88a5
--- /dev/null
+++ b/Documentation/Help/M_Tests_Passwords_PasswordTests_PasswordCreation_WithInvalidSalt_ReturnsEmptyHash.md
@@ -0,0 +1,30 @@
+# PasswordCreation_WithInvalidSalt_ReturnsEmptyHash Method
+
+
+\[Missing <summary> documentation for "M:Tests.Passwords.PasswordTests.PasswordCreation_WithInvalidSalt_ReturnsEmptyHash"\]
+
+
+
+## Definition
+**Namespace:** Tests
+**Assembly:** Tests (in Tests.exe) Version: 1.0.0
+
+**C#**
+``` C#
+[TestAttribute]
+public void PasswordCreation_WithInvalidSalt_ReturnsEmptyHash()
+```
+**F#**
+``` F#
+[]
+member PasswordCreation_WithInvalidSalt_ReturnsEmptyHash : unit -> unit
+```
+
+
+
+## See Also
+
+
+#### Reference
+Passwords.PasswordTests Class
+Tests Namespace
diff --git a/Documentation/Help/M_Tests_Passwords_PasswordTests_PasswordCreation_WithPbkdf2Algorithm_CreatesValidHash.md b/Documentation/Help/M_Tests_Passwords_PasswordTests_PasswordCreation_WithPbkdf2Algorithm_CreatesValidHash.md
new file mode 100644
index 0000000..a812512
--- /dev/null
+++ b/Documentation/Help/M_Tests_Passwords_PasswordTests_PasswordCreation_WithPbkdf2Algorithm_CreatesValidHash.md
@@ -0,0 +1,30 @@
+# PasswordCreation_WithPbkdf2Algorithm_CreatesValidHash Method
+
+
+\[Missing <summary> documentation for "M:Tests.Passwords.PasswordTests.PasswordCreation_WithPbkdf2Algorithm_CreatesValidHash"\]
+
+
+
+## Definition
+**Namespace:** Tests
+**Assembly:** Tests (in Tests.exe) Version: 1.0.0
+
+**C#**
+``` C#
+[TestAttribute]
+public void PasswordCreation_WithPbkdf2Algorithm_CreatesValidHash()
+```
+**F#**
+``` F#
+[]
+member PasswordCreation_WithPbkdf2Algorithm_CreatesValidHash : unit -> unit
+```
+
+
+
+## See Also
+
+
+#### Reference
+Passwords.PasswordTests Class
+Tests Namespace
diff --git a/Documentation/Help/M_Tests_Passwords_PasswordTests_PasswordEquality_DifferentPasswords_AreNotEqual.md b/Documentation/Help/M_Tests_Passwords_PasswordTests_PasswordEquality_DifferentPasswords_AreNotEqual.md
new file mode 100644
index 0000000..1112f63
--- /dev/null
+++ b/Documentation/Help/M_Tests_Passwords_PasswordTests_PasswordEquality_DifferentPasswords_AreNotEqual.md
@@ -0,0 +1,30 @@
+# PasswordEquality_DifferentPasswords_AreNotEqual Method
+
+
+\[Missing <summary> documentation for "M:Tests.Passwords.PasswordTests.PasswordEquality_DifferentPasswords_AreNotEqual"\]
+
+
+
+## Definition
+**Namespace:** Tests
+**Assembly:** Tests (in Tests.exe) Version: 1.0.0
+
+**C#**
+``` C#
+[TestAttribute]
+public void PasswordEquality_DifferentPasswords_AreNotEqual()
+```
+**F#**
+``` F#
+[]
+member PasswordEquality_DifferentPasswords_AreNotEqual : unit -> unit
+```
+
+
+
+## See Also
+
+
+#### Reference
+Passwords.PasswordTests Class
+Tests Namespace
diff --git a/Documentation/Help/M_Tests_Passwords_PasswordTests_PasswordEquality_DifferentSalts_AreNotEqual.md b/Documentation/Help/M_Tests_Passwords_PasswordTests_PasswordEquality_DifferentSalts_AreNotEqual.md
new file mode 100644
index 0000000..83356b3
--- /dev/null
+++ b/Documentation/Help/M_Tests_Passwords_PasswordTests_PasswordEquality_DifferentSalts_AreNotEqual.md
@@ -0,0 +1,30 @@
+# PasswordEquality_DifferentSalts_AreNotEqual Method
+
+
+\[Missing <summary> documentation for "M:Tests.Passwords.PasswordTests.PasswordEquality_DifferentSalts_AreNotEqual"\]
+
+
+
+## Definition
+**Namespace:** Tests
+**Assembly:** Tests (in Tests.exe) Version: 1.0.0
+
+**C#**
+``` C#
+[TestAttribute]
+public void PasswordEquality_DifferentSalts_AreNotEqual()
+```
+**F#**
+``` F#
+[]
+member PasswordEquality_DifferentSalts_AreNotEqual : unit -> unit
+```
+
+
+
+## See Also
+
+
+#### Reference
+Passwords.PasswordTests Class
+Tests Namespace
diff --git a/Documentation/Help/M_Tests_Passwords_PasswordTests_PasswordEquality_SamePasswordAndSalt_AreEqual.md b/Documentation/Help/M_Tests_Passwords_PasswordTests_PasswordEquality_SamePasswordAndSalt_AreEqual.md
new file mode 100644
index 0000000..f1d5c29
--- /dev/null
+++ b/Documentation/Help/M_Tests_Passwords_PasswordTests_PasswordEquality_SamePasswordAndSalt_AreEqual.md
@@ -0,0 +1,30 @@
+# PasswordEquality_SamePasswordAndSalt_AreEqual Method
+
+
+\[Missing <summary> documentation for "M:Tests.Passwords.PasswordTests.PasswordEquality_SamePasswordAndSalt_AreEqual"\]
+
+
+
+## Definition
+**Namespace:** Tests
+**Assembly:** Tests (in Tests.exe) Version: 1.0.0
+
+**C#**
+``` C#
+[TestAttribute]
+public void PasswordEquality_SamePasswordAndSalt_AreEqual()
+```
+**F#**
+``` F#
+[]
+member PasswordEquality_SamePasswordAndSalt_AreEqual : unit -> unit
+```
+
+
+
+## See Also
+
+
+#### Reference
+Passwords.PasswordTests Class
+Tests Namespace
diff --git a/Documentation/Help/M_Tests_Passwords_PasswordTests_ToString_ReturnsCorrectFormat.md b/Documentation/Help/M_Tests_Passwords_PasswordTests_ToString_ReturnsCorrectFormat.md
new file mode 100644
index 0000000..24355f7
--- /dev/null
+++ b/Documentation/Help/M_Tests_Passwords_PasswordTests_ToString_ReturnsCorrectFormat.md
@@ -0,0 +1,30 @@
+# ToString_ReturnsCorrectFormat Method
+
+
+\[Missing <summary> documentation for "M:Tests.Passwords.PasswordTests.ToString_ReturnsCorrectFormat"\]
+
+
+
+## Definition
+**Namespace:** Tests
+**Assembly:** Tests (in Tests.exe) Version: 1.0.0
+
+**C#**
+``` C#
+[TestAttribute]
+public void ToString_ReturnsCorrectFormat()
+```
+**F#**
+``` F#
+[]
+member ToString_ReturnsCorrectFormat : unit -> unit
+```
+
+
+
+## See Also
+
+
+#### Reference
+Passwords.PasswordTests Class
+Tests Namespace
diff --git a/Documentation/Help/M_Tests_Passwords_PasswordTests__ctor.md b/Documentation/Help/M_Tests_Passwords_PasswordTests__ctor.md
new file mode 100644
index 0000000..70cc68e
--- /dev/null
+++ b/Documentation/Help/M_Tests_Passwords_PasswordTests__ctor.md
@@ -0,0 +1,28 @@
+# Passwords.PasswordTests Constructor
+
+
+Initializes a new instance of the Passwords.PasswordTests class
+
+
+
+## Definition
+**Namespace:** Tests
+**Assembly:** Tests (in Tests.exe) Version: 1.0.0
+
+**C#**
+``` C#
+public PasswordTests()
+```
+**F#**
+``` F#
+new : unit -> PasswordTests
+```
+
+
+
+## See Also
+
+
+#### Reference
+Passwords.PasswordTests Class
+Tests Namespace
diff --git a/Documentation/Help/M_Tests_Passwords__ctor.md b/Documentation/Help/M_Tests_Passwords__ctor.md
new file mode 100644
index 0000000..305febf
--- /dev/null
+++ b/Documentation/Help/M_Tests_Passwords__ctor.md
@@ -0,0 +1,28 @@
+# Passwords Constructor
+
+
+Initializes a new instance of the Passwords class
+
+
+
+## Definition
+**Namespace:** Tests
+**Assembly:** Tests (in Tests.exe) Version: 1.0.0
+
+**C#**
+``` C#
+public Passwords()
+```
+**F#**
+``` F#
+new : unit -> Passwords
+```
+
+
+
+## See Also
+
+
+#### Reference
+Passwords Class
+Tests Namespace
diff --git a/Documentation/Help/M_Tests_StringExtensions_IfNullOrEmpty_ShouldReturnOriginalStringWhenValueIsNotNullNorEmpty.md b/Documentation/Help/M_Tests_StringExtensions_IfNullOrEmpty_ShouldReturnOriginalStringWhenValueIsNotNullNorEmpty.md
new file mode 100644
index 0000000..f279893
--- /dev/null
+++ b/Documentation/Help/M_Tests_StringExtensions_IfNullOrEmpty_ShouldReturnOriginalStringWhenValueIsNotNullNorEmpty.md
@@ -0,0 +1,38 @@
+# IfNullOrEmpty_ShouldReturnOriginalStringWhenValueIsNotNullNorEmpty Method
+
+
+\[Missing <summary> documentation for "M:Tests.StringExtensions.IfNullOrEmpty_ShouldReturnOriginalStringWhenValueIsNotNullNorEmpty(System.String)"\]
+
+
+
+## Definition
+**Namespace:** Tests
+**Assembly:** Tests (in Tests.exe) Version: 1.0.0
+
+**C#**
+``` C#
+[TestCaseAttribute("Not Empty")]
+[TestCaseAttribute("")]
+public void IfNullOrEmpty_ShouldReturnOriginalStringWhenValueIsNotNullNorEmpty(
+ string value
+)
+```
+**F#**
+``` F#
+[]
+[]
+member IfNullOrEmpty_ShouldReturnOriginalStringWhenValueIsNotNullNorEmpty :
+ value : string -> unit
+```
+
+
+
+#### Parameters
+- String
- \[Missing <param name="value"/> documentation for "M:Tests.StringExtensions.IfNullOrEmpty_ShouldReturnOriginalStringWhenValueIsNotNullNorEmpty(System.String)"\]
+
+## See Also
+
+
+#### Reference
+StringExtensions Class
+Tests Namespace
diff --git a/Documentation/Help/M_Tests_StringExtensions_IfNullOrEmpty_ShouldReturnReplacementWhenValueIsNullOrEmpty.md b/Documentation/Help/M_Tests_StringExtensions_IfNullOrEmpty_ShouldReturnReplacementWhenValueIsNullOrEmpty.md
new file mode 100644
index 0000000..8f92590
--- /dev/null
+++ b/Documentation/Help/M_Tests_StringExtensions_IfNullOrEmpty_ShouldReturnReplacementWhenValueIsNullOrEmpty.md
@@ -0,0 +1,36 @@
+# IfNullOrEmpty_ShouldReturnReplacementWhenValueIsNullOrEmpty Method
+
+
+\[Missing <summary> documentation for "M:Tests.StringExtensions.IfNullOrEmpty_ShouldReturnReplacementWhenValueIsNullOrEmpty(System.String)"\]
+
+
+
+## Definition
+**Namespace:** Tests
+**Assembly:** Tests (in Tests.exe) Version: 1.0.0
+
+**C#**
+``` C#
+[TestCaseAttribute("")]
+public void IfNullOrEmpty_ShouldReturnReplacementWhenValueIsNullOrEmpty(
+ string value
+)
+```
+**F#**
+``` F#
+[]
+member IfNullOrEmpty_ShouldReturnReplacementWhenValueIsNullOrEmpty :
+ value : string -> unit
+```
+
+
+
+#### Parameters
+- String
- \[Missing <param name="value"/> documentation for "M:Tests.StringExtensions.IfNullOrEmpty_ShouldReturnReplacementWhenValueIsNullOrEmpty(System.String)"\]
+
+## See Also
+
+
+#### Reference
+StringExtensions Class
+Tests Namespace
diff --git a/Documentation/Help/M_Tests_StringExtensions_IfNullOrWhiteSpace_ShouldReturnOriginalStringWhenValueIsNotNullNorWhitespace.md b/Documentation/Help/M_Tests_StringExtensions_IfNullOrWhiteSpace_ShouldReturnOriginalStringWhenValueIsNotNullNorWhitespace.md
new file mode 100644
index 0000000..4bf8262
--- /dev/null
+++ b/Documentation/Help/M_Tests_StringExtensions_IfNullOrWhiteSpace_ShouldReturnOriginalStringWhenValueIsNotNullNorWhitespace.md
@@ -0,0 +1,38 @@
+# IfNullOrWhiteSpace_ShouldReturnOriginalStringWhenValueIsNotNullNorWhitespace Method
+
+
+\[Missing <summary> documentation for "M:Tests.StringExtensions.IfNullOrWhiteSpace_ShouldReturnOriginalStringWhenValueIsNotNullNorWhitespace(System.String)"\]
+
+
+
+## Definition
+**Namespace:** Tests
+**Assembly:** Tests (in Tests.exe) Version: 1.0.0
+
+**C#**
+``` C#
+[TestCaseAttribute("Not Empty")]
+[TestCaseAttribute(" Tab")]
+public void IfNullOrWhiteSpace_ShouldReturnOriginalStringWhenValueIsNotNullNorWhitespace(
+ string value
+)
+```
+**F#**
+``` F#
+[]
+[]
+member IfNullOrWhiteSpace_ShouldReturnOriginalStringWhenValueIsNotNullNorWhitespace :
+ value : string -> unit
+```
+
+
+
+#### Parameters
+- String
- \[Missing <param name="value"/> documentation for "M:Tests.StringExtensions.IfNullOrWhiteSpace_ShouldReturnOriginalStringWhenValueIsNotNullNorWhitespace(System.String)"\]
+
+## See Also
+
+
+#### Reference
+StringExtensions Class
+Tests Namespace
diff --git a/Documentation/Help/M_Tests_StringExtensions_IfNullOrWhiteSpace_ShouldReturnReplacementWhenValueIsNullOrWhitespace.md b/Documentation/Help/M_Tests_StringExtensions_IfNullOrWhiteSpace_ShouldReturnReplacementWhenValueIsNullOrWhitespace.md
new file mode 100644
index 0000000..8e9a828
--- /dev/null
+++ b/Documentation/Help/M_Tests_StringExtensions_IfNullOrWhiteSpace_ShouldReturnReplacementWhenValueIsNullOrWhitespace.md
@@ -0,0 +1,38 @@
+# IfNullOrWhiteSpace_ShouldReturnReplacementWhenValueIsNullOrWhitespace Method
+
+
+\[Missing <summary> documentation for "M:Tests.StringExtensions.IfNullOrWhiteSpace_ShouldReturnReplacementWhenValueIsNullOrWhitespace(System.String)"\]
+
+
+
+## Definition
+**Namespace:** Tests
+**Assembly:** Tests (in Tests.exe) Version: 1.0.0
+
+**C#**
+``` C#
+[TestCaseAttribute("")]
+[TestCaseAttribute("")]
+public void IfNullOrWhiteSpace_ShouldReturnReplacementWhenValueIsNullOrWhitespace(
+ string value
+)
+```
+**F#**
+``` F#
+[]
+[]
+member IfNullOrWhiteSpace_ShouldReturnReplacementWhenValueIsNullOrWhitespace :
+ value : string -> unit
+```
+
+
+
+#### Parameters
+- String
- \[Missing <param name="value"/> documentation for "M:Tests.StringExtensions.IfNullOrWhiteSpace_ShouldReturnReplacementWhenValueIsNullOrWhitespace(System.String)"\]
+
+## See Also
+
+
+#### Reference
+StringExtensions Class
+Tests Namespace
diff --git a/Documentation/Help/M_Tests_StringExtensions_Setup.md b/Documentation/Help/M_Tests_StringExtensions_Setup.md
new file mode 100644
index 0000000..d0100f1
--- /dev/null
+++ b/Documentation/Help/M_Tests_StringExtensions_Setup.md
@@ -0,0 +1,30 @@
+# Setup Method
+
+
+\[Missing <summary> documentation for "M:Tests.StringExtensions.Setup"\]
+
+
+
+## Definition
+**Namespace:** Tests
+**Assembly:** Tests (in Tests.exe) Version: 1.0.0
+
+**C#**
+``` C#
+[SetUpAttribute]
+public void Setup()
+```
+**F#**
+``` F#
+[]
+member Setup : unit -> unit
+```
+
+
+
+## See Also
+
+
+#### Reference
+StringExtensions Class
+Tests Namespace
diff --git a/Documentation/Help/M_Tests_StringExtensions__ctor.md b/Documentation/Help/M_Tests_StringExtensions__ctor.md
new file mode 100644
index 0000000..b85fc54
--- /dev/null
+++ b/Documentation/Help/M_Tests_StringExtensions__ctor.md
@@ -0,0 +1,28 @@
+# StringExtensions Constructor
+
+
+Initializes a new instance of the StringExtensions class
+
+
+
+## Definition
+**Namespace:** Tests
+**Assembly:** Tests (in Tests.exe) Version: 1.0.0
+
+**C#**
+``` C#
+public StringExtensions()
+```
+**F#**
+``` F#
+new : unit -> StringExtensions
+```
+
+
+
+## See Also
+
+
+#### Reference
+StringExtensions Class
+Tests Namespace
diff --git a/Documentation/Help/Methods_T_Tests_Passwords.md b/Documentation/Help/Methods_T_Tests_Passwords.md
new file mode 100644
index 0000000..874c419
--- /dev/null
+++ b/Documentation/Help/Methods_T_Tests_Passwords.md
@@ -0,0 +1,33 @@
+# Passwords Methods
+
+
+
+
+## Methods
+
+
+Equals |
+Determines whether the specified object is equal to the current object. (Inherited from Object) |
+
+Finalize |
+Allows an object to try to free resources and perform other cleanup operations before it is reclaimed by garbage collection. (Inherited from Object) |
+
+GetHashCode |
+Serves as the default hash function. (Inherited from Object) |
+
+GetType |
+Gets the Type of the current instance. (Inherited from Object) |
+
+MemberwiseClone |
+Creates a shallow copy of the current Object. (Inherited from Object) |
+
+ToString |
+Returns a string that represents the current object. (Inherited from Object) |
+
+
+## See Also
+
+
+#### Reference
+Passwords Class
+Tests Namespace
diff --git a/Documentation/Help/Methods_T_Tests_Passwords_PasswordTests.md b/Documentation/Help/Methods_T_Tests_Passwords_PasswordTests.md
new file mode 100644
index 0000000..27841bb
--- /dev/null
+++ b/Documentation/Help/Methods_T_Tests_Passwords_PasswordTests.md
@@ -0,0 +1,54 @@
+# PasswordTests Methods
+
+
+
+
+## Methods
+
+
+## See Also
+
+
+#### Reference
+Passwords.PasswordTests Class
+Tests Namespace
diff --git a/Documentation/Help/Methods_T_Tests_StringExtensions.md b/Documentation/Help/Methods_T_Tests_StringExtensions.md
new file mode 100644
index 0000000..338add9
--- /dev/null
+++ b/Documentation/Help/Methods_T_Tests_StringExtensions.md
@@ -0,0 +1,48 @@
+# StringExtensions Methods
+
+
+
+
+## Methods
+
+
+## See Also
+
+
+#### Reference
+StringExtensions Class
+Tests Namespace
diff --git a/Documentation/Help/N_Tests.md b/Documentation/Help/N_Tests.md
new file mode 100644
index 0000000..8169aaf
--- /dev/null
+++ b/Documentation/Help/N_Tests.md
@@ -0,0 +1,19 @@
+# Tests Namespace
+
+
+\[Missing <summary> documentation for "N:Tests"\]
+
+
+
+## Classes
+
\ No newline at end of file
diff --git a/Documentation/Help/R_Project_Documentation.md b/Documentation/Help/R_Project_Documentation.md
index 48d9d88..db0c8eb 100644
--- a/Documentation/Help/R_Project_Documentation.md
+++ b/Documentation/Help/R_Project_Documentation.md
@@ -20,4 +20,7 @@
CapyKit.Helpers |
|
+
+Tests |
+ |
\ No newline at end of file
diff --git a/Documentation/Help/T_Tests_Passwords.md b/Documentation/Help/T_Tests_Passwords.md
new file mode 100644
index 0000000..da0d5da
--- /dev/null
+++ b/Documentation/Help/T_Tests_Passwords.md
@@ -0,0 +1,59 @@
+# Passwords Class
+
+
+\[Missing <summary> documentation for "T:Tests.Passwords"\]
+
+
+
+## Definition
+**Namespace:** Tests
+**Assembly:** Tests (in Tests.exe) Version: 1.0.0
+
+**C#**
+``` C#
+internal class Passwords
+```
+**F#**
+``` F#
+type Passwords = class end
+```
+
+Inheritance | Object → Passwords |
+
+
+
+
+## Constructors
+
+
+Passwords |
+Initializes a new instance of the Passwords class |
+
+
+## Methods
+
+
+Equals |
+Determines whether the specified object is equal to the current object. (Inherited from Object) |
+
+Finalize |
+Allows an object to try to free resources and perform other cleanup operations before it is reclaimed by garbage collection. (Inherited from Object) |
+
+GetHashCode |
+Serves as the default hash function. (Inherited from Object) |
+
+GetType |
+Gets the Type of the current instance. (Inherited from Object) |
+
+MemberwiseClone |
+Creates a shallow copy of the current Object. (Inherited from Object) |
+
+ToString |
+Returns a string that represents the current object. (Inherited from Object) |
+
+
+## See Also
+
+
+#### Reference
+Tests Namespace
diff --git a/Documentation/Help/T_Tests_Passwords_PasswordTests.md b/Documentation/Help/T_Tests_Passwords_PasswordTests.md
new file mode 100644
index 0000000..3fbdbb6
--- /dev/null
+++ b/Documentation/Help/T_Tests_Passwords_PasswordTests.md
@@ -0,0 +1,82 @@
+# Passwords.PasswordTests Class
+
+
+\[Missing <summary> documentation for "T:Tests.Passwords.PasswordTests"\]
+
+
+
+## Definition
+**Namespace:** Tests
+**Assembly:** Tests (in Tests.exe) Version: 1.0.0
+
+**C#**
+``` C#
+[TestFixtureAttribute]
+public class PasswordTests
+```
+**F#**
+``` F#
+[]
+type PasswordTests = class end
+```
+
+Inheritance | Object → Passwords.PasswordTests |
+
+
+
+
+## Constructors
+
+
+## Methods
+
+
+## See Also
+
+
+#### Reference
+Tests Namespace
diff --git a/Documentation/Help/T_Tests_StringExtensions.md b/Documentation/Help/T_Tests_StringExtensions.md
new file mode 100644
index 0000000..78b0a94
--- /dev/null
+++ b/Documentation/Help/T_Tests_StringExtensions.md
@@ -0,0 +1,83 @@
+# StringExtensions Class
+
+
+\[Missing <summary> documentation for "T:Tests.StringExtensions"\]
+
+
+
+## Definition
+**Namespace:** Tests
+**Assembly:** Tests (in Tests.exe) Version: 1.0.0
+
+**C#**
+``` C#
+[TestFixtureAttribute]
+internal class StringExtensions
+```
+**F#**
+``` F#
+[]
+type StringExtensions = class end
+```
+
+Inheritance | Object → StringExtensions |
+
+
+
+
+## Constructors
+
+
+## Methods
+
+
+## Fields
+
+
+## See Also
+
+
+#### Reference
+Tests Namespace
diff --git a/Documentation/Help/Working/_InheritedDocs_.xml b/Documentation/Help/Working/_InheritedDocs_.xml
new file mode 100644
index 0000000..82ddca8
--- /dev/null
+++ b/Documentation/Help/Working/_InheritedDocs_.xml
@@ -0,0 +1,19 @@
+
+
+ _InheritedDocs_
+
+
+
+
+Determines whether the specified object is equal to the current object.The object to compare with the current object. if the specified object is equal to the current object; otherwise, .
+
+Returns a string that represents the current object.A string that represents the current object.
+
+
+
+
+
+
+ Gets the name of the algorithm.
+
+
\ No newline at end of file
diff --git a/Documentation/Help/_Sidebar.md b/Documentation/Help/_Sidebar.md
index 60ab0d3..c03984b 100644
--- a/Documentation/Help/_Sidebar.md
+++ b/Documentation/Help/_Sidebar.md
@@ -229,3 +229,27 @@
- [accessor Field](F_CapyKit_Helpers_SettingsHelper_accessor.md)
- [detector Field](F_CapyKit_Helpers_SettingsHelper_detector.md)
- [ValidCharacterCollection Enumeration](T_CapyKit_Helpers_ValidCharacterCollection.md)
+ - [Tests Namespace](N_Tests.md)
+ - [Passwords Class](T_Tests_Passwords.md)
+ - [Passwords Constructor](M_Tests_Passwords__ctor.md)
+ - [Passwords Methods](Methods_T_Tests_Passwords.md)
+ - [Passwords.PasswordTests Class](T_Tests_Passwords_PasswordTests.md)
+ - [Passwords.PasswordTests Constructor](M_Tests_Passwords_PasswordTests__ctor.md)
+ - [PasswordTests Methods](Methods_T_Tests_Passwords_PasswordTests.md)
+ - [GenerateSalt Method](M_Tests_Passwords_PasswordTests_GenerateSalt.md)
+ - [PasswordCreation_WithInvalidSalt_ReturnsEmptyHash Method](M_Tests_Passwords_PasswordTests_PasswordCreation_WithInvalidSalt_ReturnsEmptyHash.md)
+ - [PasswordCreation_WithPbkdf2Algorithm_CreatesValidHash Method](M_Tests_Passwords_PasswordTests_PasswordCreation_WithPbkdf2Algorithm_CreatesValidHash.md)
+ - [PasswordEquality_DifferentPasswords_AreNotEqual Method](M_Tests_Passwords_PasswordTests_PasswordEquality_DifferentPasswords_AreNotEqual.md)
+ - [PasswordEquality_DifferentSalts_AreNotEqual Method](M_Tests_Passwords_PasswordTests_PasswordEquality_DifferentSalts_AreNotEqual.md)
+ - [PasswordEquality_SamePasswordAndSalt_AreEqual Method](M_Tests_Passwords_PasswordTests_PasswordEquality_SamePasswordAndSalt_AreEqual.md)
+ - [ToString_ReturnsCorrectFormat Method](M_Tests_Passwords_PasswordTests_ToString_ReturnsCorrectFormat.md)
+ - [StringExtensions Class](T_Tests_StringExtensions.md)
+ - [StringExtensions Constructor](M_Tests_StringExtensions__ctor.md)
+ - [StringExtensions Methods](Methods_T_Tests_StringExtensions.md)
+ - [IfNullOrEmpty_ShouldReturnOriginalStringWhenValueIsNotNullNorEmpty Method](M_Tests_StringExtensions_IfNullOrEmpty_ShouldReturnOriginalStringWhenValueIsNotNullNorEmpty.md)
+ - [IfNullOrEmpty_ShouldReturnReplacementWhenValueIsNullOrEmpty Method](M_Tests_StringExtensions_IfNullOrEmpty_ShouldReturnReplacementWhenValueIsNullOrEmpty.md)
+ - [IfNullOrWhiteSpace_ShouldReturnOriginalStringWhenValueIsNotNullNorWhitespace Method](M_Tests_StringExtensions_IfNullOrWhiteSpace_ShouldReturnOriginalStringWhenValueIsNotNullNorWhitespace.md)
+ - [IfNullOrWhiteSpace_ShouldReturnReplacementWhenValueIsNullOrWhitespace Method](M_Tests_StringExtensions_IfNullOrWhiteSpace_ShouldReturnReplacementWhenValueIsNullOrWhitespace.md)
+ - [Setup Method](M_Tests_StringExtensions_Setup.md)
+ - [StringExtensions Fields](Fields_T_Tests_StringExtensions.md)
+ - [Replacement Field](F_Tests_StringExtensions_Replacement.md)
diff --git a/Tests/Passwords.cs b/Tests/Passwords.cs
new file mode 100644
index 0000000..aaa5f1b
--- /dev/null
+++ b/Tests/Passwords.cs
@@ -0,0 +1,127 @@
+using CapyKit;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tests
+{
+ internal class Passwords
+ {
+ [TestFixture]
+ public class PasswordTests
+ {
+ private static byte[] GenerateSalt(int size = 16)
+ {
+ var salt = new byte[size];
+ using (var rng = new System.Security.Cryptography.RNGCryptoServiceProvider())
+ {
+ rng.GetBytes(salt);
+ }
+ return salt;
+ }
+
+ [Test]
+ public void PasswordCreation_WithPbkdf2Algorithm_CreatesValidHash()
+ {
+ // Arrange
+ var passwordText = "mySecurePassword";
+ var salt = GenerateSalt();
+ var algorithm = Password.Pbkdf2Algorithm;
+
+ // Act
+ var password = new Password(passwordText, salt, algorithm);
+
+ // Assert
+ Assert.IsNotNull(password.Hash);
+ Assert.IsNotEmpty(password.Hash);
+ Assert.AreEqual(salt, password.Salt);
+ Assert.AreEqual(algorithm, password.Algorithm);
+ }
+
+ [Test]
+ public void PasswordEquality_SamePasswordAndSalt_AreEqual()
+ {
+ // Arrange
+ var passwordText = "mySecurePassword";
+ var salt = GenerateSalt();
+ var algorithm = Password.Pbkdf2Algorithm;
+
+ var password1 = new Password(passwordText, salt, algorithm);
+ var password2 = new Password(passwordText, salt, algorithm);
+
+ // Act & Assert
+ Assert.AreEqual(password1, password2);
+ Assert.IsTrue(password1 == password2);
+ }
+
+ [Test]
+ public void PasswordEquality_DifferentPasswords_AreNotEqual()
+ {
+ // Arrange
+ var salt = GenerateSalt();
+ var algorithm = new Pbkdf2Algorithm();
+
+ var password1 = new Password("passwordOne", salt, algorithm);
+ var password2 = new Password("passwordTwo", salt, algorithm);
+
+ // Act & Assert
+ Assert.AreNotEqual(password1, password2);
+ Assert.IsTrue(password1 != password2);
+ }
+
+ [Test]
+ public void PasswordEquality_DifferentSalts_AreNotEqual()
+ {
+ // Arrange
+ var passwordText = "mySecurePassword";
+ var salt1 = GenerateSalt();
+ var salt2 = GenerateSalt();
+ var algorithm = Password.Pbkdf2Algorithm;
+
+ var password1 = new Password(passwordText, salt1, algorithm);
+ var password2 = new Password(passwordText, salt2, algorithm);
+
+ // Act & Assert
+ Assert.AreNotEqual(password1, password2);
+ Assert.IsTrue(password1 != password2);
+ }
+
+ [Test]
+ public void ToString_ReturnsCorrectFormat()
+ {
+ // Arrange
+ var passwordText = "mySecurePassword";
+ var salt = GenerateSalt();
+ var algorithm = Password.Pbkdf2Algorithm;
+
+ var password = new Password(passwordText, salt, algorithm);
+
+ // Act
+ var result = password.ToString();
+
+ // Assert
+ Assert.IsTrue(result.Contains("Hash:"));
+ Assert.IsTrue(result.Contains("Salt:"));
+ Assert.IsTrue(result.Contains("Algorithm: Pbkdf2"));
+ }
+
+ [Test]
+ public void PasswordCreation_WithInvalidSalt_ReturnsEmptyHash()
+ {
+ // Arrange
+ var passwordText = "mySecurePassword";
+ byte[] invalidSalt = null; // Invalid salt
+ var algorithm = new Pbkdf2Algorithm();
+
+ // Act
+ var password = new Password(passwordText, invalidSalt, algorithm);
+
+ // Assert
+ Assert.IsNotNull(password.Hash);
+ Assert.IsEmpty(password.Hash);
+ }
+ }
+ }
+}
diff --git a/Tests/StringExtensions.cs b/Tests/StringExtensions.cs
new file mode 100644
index 0000000..266f1fa
--- /dev/null
+++ b/Tests/StringExtensions.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System;
+using CapyKit.Extensions;
+using NUnit.Framework;
+
+namespace Tests
+{
+ [TestFixture]
+ internal class StringExtensions
+ {
+ private const string Replacement = "Replaced";
+
+ [SetUp]
+ public void Setup()
+ {
+ // No setup required for this test fixture.
+ }
+
+ #region IfNullOrEmpty
+
+ [TestCase("")]
+ public void IfNullOrEmpty_ShouldReturnReplacementWhenValueIsNullOrEmpty(string value)
+ {
+ var result = value.IfNullOrEmpty(Replacement);
+
+ Assert.AreEqual(Replacement, result);
+ }
+
+ [TestCase("Not Empty")]
+ [TestCase(" ")] // Whitespace is not considered empty
+ public void IfNullOrEmpty_ShouldReturnOriginalStringWhenValueIsNotNullNorEmpty(string value)
+ {
+ var result = value.IfNullOrEmpty(Replacement);
+
+ Assert.AreEqual(value, result);
+ }
+
+ #endregion
+
+ #region IfNullOrWhiteSpace
+
+ [TestCase("")]
+ [TestCase(" ")] // Whitespace is considered empty
+ public void IfNullOrWhiteSpace_ShouldReturnReplacementWhenValueIsNullOrWhitespace(string value)
+ {
+ var result = value.IfNullOrWhiteSpace(Replacement);
+
+ Assert.AreEqual(Replacement, result);
+ }
+
+ [TestCase("Not Empty")]
+ [TestCase("\tTab")] // Non-whitespace character is not considered empty
+ public void IfNullOrWhiteSpace_ShouldReturnOriginalStringWhenValueIsNotNullNorWhitespace(string value)
+ {
+ var result = value.IfNullOrWhiteSpace(Replacement);
+
+ Assert.AreEqual(value, result);
+ }
+
+ #endregion
+ }
+}
diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj
new file mode 100644
index 0000000..d6604e7
--- /dev/null
+++ b/Tests/Tests.csproj
@@ -0,0 +1,28 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+ false
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+