From e033d4d22b41de896cb25927f95b2338bcfef585 Mon Sep 17 00:00:00 2001
From: LuisMSuarez <140195810+LuisMSuarez@users.noreply.github.com>
Date: Wed, 27 Aug 2025 12:43:54 -0700
Subject: [PATCH 1/3] Updating namespaces
---
HuffmanCompressor.sln | 8 +-
HuffmanCompressor/BitReader.cs | 77 ++--
HuffmanCompressor/BitWriter.cs | 125 +++---
HuffmanCompressor/FrequencyCounter.cs | 198 +++++----
...ib.csproj => HuffmanCompressor.Lib.csproj} | 0
HuffmanCompressor/HuffmanCompressor.cs | 387 +++++++++---------
HuffmanCompressor/IFileCompressor.cs | 17 +-
HuffmanCompressor/Node.cs | 121 +++---
HuffmanCompressor/Properties/AssemblyInfo.cs | 2 +-
HuffmanCompressorCmd/AssemblyInfo.cs | 2 +-
...md.csproj => HuffmanCompressor.Cmd.csproj} | 2 +-
HuffmanCompressorCmd/Program.cs | 110 +++--
HuffmanCompressorTests/EndToEndTests.cs | 78 ++--
.../FrequencyCounterTests.cs | 110 +++--
....csproj => HuffmanCompressor.Tests.csproj} | 4 +-
.../HuffmanCompressorTests.cs | 174 ++++----
HuffmanCompressorTests/ProgramTests.cs | 122 +++---
HuffmanCompressorTests/Utilities.cs | 40 +-
...j => HuffmanCompressor.WinFormsApp.csproj} | 2 +-
.../MainForm.Designer.cs | 198 +++++----
HufmannCompressorWinFormsApp/MainForm.cs | 62 ++-
HufmannCompressorWinFormsApp/Program.cs | 2 +-
22 files changed, 906 insertions(+), 935 deletions(-)
rename HuffmanCompressor/{HuffmanCompressorLib.csproj => HuffmanCompressor.Lib.csproj} (100%)
rename HuffmanCompressorCmd/{HuffmanCompressorCmd.csproj => HuffmanCompressor.Cmd.csproj} (94%)
rename HuffmanCompressorTests/{HuffmanCompressorTests.csproj => HuffmanCompressor.Tests.csproj} (97%)
rename HufmannCompressorWinFormsApp/{HuffmanCompressorWinFormsApp.csproj => HuffmanCompressor.WinFormsApp.csproj} (94%)
diff --git a/HuffmanCompressor.sln b/HuffmanCompressor.sln
index f15978b..6085d43 100644
--- a/HuffmanCompressor.sln
+++ b/HuffmanCompressor.sln
@@ -3,13 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.7.34202.233
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HuffmanCompressorLib", "HuffmanCompressor\HuffmanCompressorLib.csproj", "{93160A18-48C3-4AB8-A9C9-2EA2D2C46B01}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HuffmanCompressor.Lib", "HuffmanCompressor\HuffmanCompressor.Lib.csproj", "{93160A18-48C3-4AB8-A9C9-2EA2D2C46B01}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HuffmanCompressorTests", "HuffmanCompressorTests\HuffmanCompressorTests.csproj", "{304D0AF6-D701-40E9-8A2F-E2508A12ED5F}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HuffmanCompressor.Tests", "HuffmanCompressorTests\HuffmanCompressor.Tests.csproj", "{304D0AF6-D701-40E9-8A2F-E2508A12ED5F}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HuffmanCompressorWinFormsApp", "HufmannCompressorWinFormsApp\HuffmanCompressorWinFormsApp.csproj", "{78D7EB54-F5CB-45E8-B293-2B95EA522589}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HuffmanCompressor.WinFormsApp", "HufmannCompressorWinFormsApp\HuffmanCompressor.WinFormsApp.csproj", "{78D7EB54-F5CB-45E8-B293-2B95EA522589}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HuffmanCompressorCmd", "HuffmanCompressorCmd\HuffmanCompressorCmd.csproj", "{567B674B-79D9-4331-A6D6-A13735DA3327}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HuffmanCompressor.Cmd", "HuffmanCompressorCmd\HuffmanCompressor.Cmd.csproj", "{567B674B-79D9-4331-A6D6-A13735DA3327}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
diff --git a/HuffmanCompressor/BitReader.cs b/HuffmanCompressor/BitReader.cs
index 6bbdc28..9d1fb35 100644
--- a/HuffmanCompressor/BitReader.cs
+++ b/HuffmanCompressor/BitReader.cs
@@ -1,50 +1,49 @@
-namespace HuffmanCompressorLib
+namespace HuffmanCompressor.Lib;
+
+///
+/// Provides functionality to read individual bits from an input file stream.
+///
+internal class BitReader
{
+ private int bitIndex;
+ private byte currentByte;
+ private readonly FileStream fileHandle;
+
///
- /// Provides functionality to read individual bits from an input file stream.
+ /// Creates an instance of class.
///
- internal class BitReader
+ /// File stream to which the reader will read bits from.
+ public BitReader(FileStream fileHandle)
{
- private int bitIndex;
- private byte currentByte;
- private readonly FileStream fileHandle;
-
- ///
- /// Creates an instance of class.
- ///
- /// File stream to which the reader will read bits from.
- public BitReader(FileStream fileHandle)
- {
- ArgumentNullException.ThrowIfNull(fileHandle);
- this.bitIndex = 8;
- this.currentByte = 0x00;
- this.fileHandle = fileHandle;
- }
+ ArgumentNullException.ThrowIfNull(fileHandle);
+ this.bitIndex = 8;
+ this.currentByte = 0x00;
+ this.fileHandle = fileHandle;
+ }
- ///
- /// Reads a bit from the file.
- ///
- /// Bit represented as a '0' or '1' character.
- /// If the end of the stream is reached while attempting to read.
- public char ReadNextBit()
+ ///
+ /// Reads a bit from the file.
+ ///
+ /// Bit represented as a '0' or '1' character.
+ /// If the end of the stream is reached while attempting to read.
+ public char ReadNextBit()
+ {
+ // Read 1 byte from the input file stream at a time, and use an index to return each bit from the byte.
+ // When we get to the last bit, read the next byte and continue until end of file
+ if (this.bitIndex >= 8)
{
- // Read 1 byte from the input file stream at a time, and use an index to return each bit from the byte.
- // When we get to the last bit, read the next byte and continue until end of file
- if (this.bitIndex >= 8)
+ var byteValue = this.fileHandle.ReadByte();
+ if (byteValue == -1)
{
- var byteValue = this.fileHandle.ReadByte();
- if (byteValue == -1)
- {
- throw new EndOfStreamException("Attempting to read past the end of the stream!");
- }
- this.currentByte = (byte)byteValue;
- this.bitIndex = 0;
+ throw new EndOfStreamException("Attempting to read past the end of the stream!");
}
-
- byte mask = (byte)(0x80 >> this.bitIndex++);
- return (this.currentByte & mask) == 0x00
- ? '0'
- : '1';
+ this.currentByte = (byte)byteValue;
+ this.bitIndex = 0;
}
+
+ byte mask = (byte)(0x80 >> this.bitIndex++);
+ return (this.currentByte & mask) == 0x00
+ ? '0'
+ : '1';
}
}
diff --git a/HuffmanCompressor/BitWriter.cs b/HuffmanCompressor/BitWriter.cs
index bab5562..db23ade 100644
--- a/HuffmanCompressor/BitWriter.cs
+++ b/HuffmanCompressor/BitWriter.cs
@@ -1,77 +1,76 @@
-namespace HuffmanCompressorLib
+namespace HuffmanCompressor.Lib;
+
+///
+/// Provides functionality to write individual bits to an output file stream.
+///
+internal class BitWriter
{
+ private int bitIndex;
+ private byte currentByte;
+ private readonly FileStream fileHandle;
+
///
- /// Provides functionality to write individual bits to an output file stream.
+ /// Creates an instance of class.
///
- internal class BitWriter
+ /// File stream to which the writer will write bits to.
+ public BitWriter(FileStream fileHandle)
{
- private int bitIndex;
- private byte currentByte;
- private readonly FileStream fileHandle;
+ ArgumentNullException.ThrowIfNull(fileHandle);
+ this.bitIndex = 0;
+ this.currentByte = 0x00;
+ this.fileHandle = fileHandle;
+ }
- ///
- /// Creates an instance of class.
- ///
- /// File stream to which the writer will write bits to.
- public BitWriter(FileStream fileHandle)
- {
- ArgumentNullException.ThrowIfNull(fileHandle);
- this.bitIndex = 0;
- this.currentByte = 0x00;
- this.fileHandle = fileHandle;
- }
+ ///
+ /// Writes bits to the output file.
+ ///
+ /// String of bits, only 0 and 1 are supported.
+ /// In case the bit string contains unsupported characters.
+ public void WriteBits(string bitString)
+ {
+ ArgumentNullException.ThrowIfNull(bitString);
- ///
- /// Writes bits to the output file.
- ///
- /// String of bits, only 0 and 1 are supported.
- /// In case the bit string contains unsupported characters.
- public void WriteBits(string bitString)
+ // Fill in currentByte from most significant bit to least significant bit by reading from input bitString
+ // until the input bitString is exhausted.
+ // As we fill out all available bits in currentByte, we flush it out to the file and start over with a fresh byte
+ for (int i = 0; i < bitString.Length; i++)
{
- ArgumentNullException.ThrowIfNull(bitString);
-
- // Fill in currentByte from most significant bit to least significant bit by reading from input bitString
- // until the input bitString is exhausted.
- // As we fill out all available bits in currentByte, we flush it out to the file and start over with a fresh byte
- for (int i = 0; i < bitString.Length; i++)
+ var bit = bitString[i];
+ switch(bit)
{
- var bit = bitString[i];
- switch(bit)
- {
- case '0':
- break;
- case '1':
- // mask a '1' on the current byte
- byte mask = 0x80;
- mask = (byte)(mask >> bitIndex);
- currentByte |= mask;
- break;
- default:
- throw new ArgumentException($"Invalid bit detected {bit}");
- }
+ case '0':
+ break;
+ case '1':
+ // mask a '1' on the current byte
+ byte mask = 0x80;
+ mask = (byte)(mask >> bitIndex);
+ currentByte |= mask;
+ break;
+ default:
+ throw new ArgumentException($"Invalid bit detected {bit}");
+ }
- if (bitIndex == 7)
- {
- // currentByte has been exhausted for all of its 8 available bits
- // commit to disk and mint a new byte to continue the process.
- fileHandle.WriteByte(currentByte);
- bitIndex = 0;
- currentByte = 0x00;
- }
- else
- {
- bitIndex++;
- }
+ if (bitIndex == 7)
+ {
+ // currentByte has been exhausted for all of its 8 available bits
+ // commit to disk and mint a new byte to continue the process.
+ fileHandle.WriteByte(currentByte);
+ bitIndex = 0;
+ currentByte = 0x00;
+ }
+ else
+ {
+ bitIndex++;
}
}
+ }
- ///
- /// Write the outstanding byte to disk, prior to closing the file handle.
- /// The remaining bits will be padding.
- ///
- public void Flush()
- {
- fileHandle.WriteByte(currentByte);
- }
+ ///
+ /// Write the outstanding byte to disk, prior to closing the file handle.
+ /// The remaining bits will be padding.
+ ///
+ public void Flush()
+ {
+ fileHandle.WriteByte(currentByte);
}
}
diff --git a/HuffmanCompressor/FrequencyCounter.cs b/HuffmanCompressor/FrequencyCounter.cs
index 919b5f0..08631f9 100644
--- a/HuffmanCompressor/FrequencyCounter.cs
+++ b/HuffmanCompressor/FrequencyCounter.cs
@@ -1,134 +1,126 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+namespace HuffmanCompressor.Lib;
-namespace HuffmanCompressorLib
+///
+/// Class to count the relative frequency of each byte in a stream of data.
+/// There is no upper bound on the number of bytes that can be counted.
+/// If the counter reaches the maximum value, the class will rebase all of the frequencies to avoid overflows.
+///
+internal class FrequencyCounter
{
+ private readonly IDictionary moduloCounter;
+ private readonly IDictionary frequencies;
+ private int multiplier;
+
///
- /// Class to count the relative frequency of each byte in a stream of data.
- /// There is no upper bound on the number of bytes that can be counted.
- /// If the counter reaches the maximum value, the class will rebase all of the frequencies to avoid overflows.
+ /// Initializes a new instance of the class.
///
- internal class FrequencyCounter
+ public FrequencyCounter()
{
- private readonly IDictionary moduloCounter;
- private readonly IDictionary frequencies;
- private int multiplier;
+ this.moduloCounter = new Dictionary();
+ this.frequencies = new Dictionary();
+ multiplier = 1;
- ///
- /// Initializes a new instance of the class.
- ///
- public FrequencyCounter()
+ // Initialize the dictionaries to make the code more straightforward in the rest of the class.
+ // Avoid overflow of counter that would lead to an infinite loop using an int
+ // https://stackoverflow.com/questions/43800147/iterating-from-minvalue-to-maxvalue-with-overflow
+ for (int i = byte.MinValue; i <= byte.MaxValue; i++)
{
- this.moduloCounter = new Dictionary();
- this.frequencies = new Dictionary();
- multiplier = 1;
+ this.moduloCounter.Add((byte)i, 0);
+ this.frequencies.Add((byte)i, 0);
+ }
+ }
- // Initialize the dictionaries to make the code more straightforward in the rest of the class.
- // Avoid overflow of counter that would lead to an infinite loop using an int
- // https://stackoverflow.com/questions/43800147/iterating-from-minvalue-to-maxvalue-with-overflow
- for (int i = byte.MinValue; i <= byte.MaxValue; i++)
- {
- this.moduloCounter.Add((byte)i, 0);
- this.frequencies.Add((byte)i, 0);
- }
+ ///
+ /// Increment the frequency of a byte by 1.
+ ///
+ /// The value to increment the frequency of.
+ public void Increment(byte value)
+ {
+ // Check to see if we have reached the rare theoretic limit for frequency counting.
+ // In that case, the best we can do is stop counting to avoid an overlfow back to 0.
+ // Note: this would still mean having read 16 million TB of a single character!
+ if (this.moduloCounter[value] == UInt32.MaxValue &&
+ this.frequencies[value] == UInt32.MaxValue)
+ {
+ return;
}
- ///
- /// Increment the frequency of a byte by 1.
- ///
- /// The value to increment the frequency of.
- public void Increment(byte value)
+ this.moduloCounter[value]++;
+ if (this.moduloCounter[value] == multiplier)
{
- // Check to see if we have reached the rare theoretic limit for frequency counting.
- // In that case, the best we can do is stop counting to avoid an overlfow back to 0.
- // Note: this would still mean having read 16 million TB of a single character!
- if (this.moduloCounter[value] == UInt32.MaxValue &&
- this.frequencies[value] == UInt32.MaxValue)
+ // If the counter is about to overflow, we call the Rebase function
+ if (this.frequencies[value] == UInt32.MaxValue)
{
- return;
+ this.Rebase();
}
-
- this.moduloCounter[value]++;
- if (this.moduloCounter[value] == multiplier)
+ else
{
- // If the counter is about to overflow, we call the Rebase function
- if (this.frequencies[value] == UInt32.MaxValue)
- {
- this.Rebase();
- }
- else
- {
- this.frequencies[value]++;
- }
-
- this.moduloCounter[value] = 0;
+ this.frequencies[value]++;
}
- }
- ///
- /// Set the frequency of a byte to a specific value.
- ///
- /// The value to set.
- /// The frequency to set.
- public void SetFrequency(byte value, UInt32 frequency)
- {
- this.frequencies[(byte)value] = frequency;
- this.moduloCounter[(byte)value] = 0;
+ this.moduloCounter[value] = 0;
}
+ }
+
+ ///
+ /// Set the frequency of a byte to a specific value.
+ ///
+ /// The value to set.
+ /// The frequency to set.
+ public void SetFrequency(byte value, UInt32 frequency)
+ {
+ this.frequencies[(byte)value] = frequency;
+ this.moduloCounter[(byte)value] = 0;
+ }
- ///
- /// Get the frequency of a byte.
- ///
- /// The value to query the frequency of
- /// Frequency of the value.
- public UInt32 GetFrequency(byte value)
+ ///
+ /// Get the frequency of a byte.
+ ///
+ /// The value to query the frequency of
+ /// Frequency of the value.
+ public UInt32 GetFrequency(byte value)
+ {
+ // First check for the case that the frequency counter has not yet been
+ // bumped up, in that case, if we ever counted the value in the modulo counter, we must return
+ // the smallest value possible, which is 1.
+ if (this.frequencies[value] == 0)
{
- // First check for the case that the frequency counter has not yet been
- // bumped up, in that case, if we ever counted the value in the modulo counter, we must return
- // the smallest value possible, which is 1.
- if (this.frequencies[value] == 0)
+ if (this.moduloCounter[value] > 0)
{
- if (this.moduloCounter[value] > 0)
- {
- return 1;
- }
-
- return 0;
+ return 1;
}
- return this.frequencies[value];
+ return 0;
}
- ///
- /// Enumerator to allow caller to cycle through frequencies.
- ///
- /// Key value pair enumaration of non-zero frequencies
- public IEnumerable> GetEnumerator()
+ return this.frequencies[value];
+ }
+
+ ///
+ /// Enumerator to allow caller to cycle through frequencies.
+ ///
+ /// Key value pair enumaration of non-zero frequencies
+ public IEnumerable> GetEnumerator()
+ {
+ for (int b = byte.MinValue; b <= byte.MaxValue; b++)
{
- for (int b = byte.MinValue; b <= byte.MaxValue; b++)
+ var frequency = this.GetFrequency((byte)b);
+ if (frequency > 0)
{
- var frequency = this.GetFrequency((byte)b);
- if (frequency > 0)
- {
- yield return new KeyValuePair((byte)b, frequency);
- }
+ yield return new KeyValuePair((byte)b, frequency);
}
}
+ }
- ///
- /// Rebases all of the frequencies uniformly by dividing them by 2
- /// This allows us to handle very high counts without risk of overflowing and still
- /// preserving statistical accuracy.
- ///
- private void Rebase()
- {
- this.frequencies.ToList().ForEach( kvp => this.frequencies[kvp.Key] /= 2 + 1);
- this.multiplier *= 2;
- }
-
+ ///
+ /// Rebases all of the frequencies uniformly by dividing them by 2
+ /// This allows us to handle very high counts without risk of overflowing and still
+ /// preserving statistical accuracy.
+ ///
+ private void Rebase()
+ {
+ this.frequencies.ToList().ForEach( kvp => this.frequencies[kvp.Key] /= 2 + 1);
+ this.multiplier *= 2;
}
+
}
diff --git a/HuffmanCompressor/HuffmanCompressorLib.csproj b/HuffmanCompressor/HuffmanCompressor.Lib.csproj
similarity index 100%
rename from HuffmanCompressor/HuffmanCompressorLib.csproj
rename to HuffmanCompressor/HuffmanCompressor.Lib.csproj
diff --git a/HuffmanCompressor/HuffmanCompressor.cs b/HuffmanCompressor/HuffmanCompressor.cs
index be80460..6f54234 100644
--- a/HuffmanCompressor/HuffmanCompressor.cs
+++ b/HuffmanCompressor/HuffmanCompressor.cs
@@ -1,252 +1,251 @@
-namespace HuffmanCompressorLib
+namespace HuffmanCompressor.Lib;
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+///
+/// Class that implements the Huffman compression algorithm.
+///
+public class HuffmanCompressor : IFileCompressor
{
- using System;
- using System.Collections.Generic;
- using System.Linq;
+ private FrequencyCounter frequencyCounter;
+ private IDictionary binaryCodeMappings;
+ private Node? treeRoot;
+
+ ///
+ /// Code to mark End of File character. Must not be a confused with a regular byte 0 to 255.
+ ///
+ private const short EndOfFileCode = -1;
///
- /// Class that implements the Huffman compression algorithm.
+ /// Initializes a new instance of the class.
///
- public class HuffmanCompressor : IFileCompressor
+ public HuffmanCompressor()
{
- private FrequencyCounter frequencyCounter;
- private IDictionary binaryCodeMappings;
- private Node? treeRoot;
-
- ///
- /// Code to mark End of File character. Must not be a confused with a regular byte 0 to 255.
- ///
- private const short EndOfFileCode = -1;
-
- ///
- /// Initializes a new instance of the class.
- ///
- public HuffmanCompressor()
- {
- this.frequencyCounter = new FrequencyCounter();
- this.binaryCodeMappings = new Dictionary();
- }
+ this.frequencyCounter = new FrequencyCounter();
+ this.binaryCodeMappings = new Dictionary();
+ }
- ///
- /// Compresses a file.
- ///
- /// File to be compressed.
- /// Path of destination (compressed) file.
- /// is .
- /// is .
+ ///
+ /// Compresses a file.
+ ///
+ /// File to be compressed.
+ /// Path of destination (compressed) file.
+ /// is .
+ /// is .
- public void Compress(string inputFilePath, string outputFilePath)
- {
- ArgumentNullException.ThrowIfNullOrWhiteSpace(inputFilePath);
- ArgumentNullException.ThrowIfNullOrWhiteSpace(outputFilePath);
+ public void Compress(string inputFilePath, string outputFilePath)
+ {
+ ArgumentNullException.ThrowIfNullOrWhiteSpace(inputFilePath);
+ ArgumentNullException.ThrowIfNullOrWhiteSpace(outputFilePath);
- this.InitializeFrequencyDictionary(inputFilePath);
- this.BuildTree();
- this.BuildBinaryCodeMappings();
- this.CompressInternal(inputFilePath, outputFilePath);
- }
+ this.InitializeFrequencyDictionary(inputFilePath);
+ this.BuildTree();
+ this.BuildBinaryCodeMappings();
+ this.CompressInternal(inputFilePath, outputFilePath);
+ }
- ///
- /// Inflates a file.
- ///
- /// File to be inflated.
- /// Path of destination (inflated) file.
- /// is .
- /// is .
+ ///
+ /// Inflates a file.
+ ///
+ /// File to be inflated.
+ /// Path of destination (inflated) file.
+ /// is .
+ /// is .
- public void Inflate(string inputFilePath, string outputFilePath)
- {
- ArgumentNullException.ThrowIfNullOrWhiteSpace(inputFilePath);
- ArgumentNullException.ThrowIfNullOrWhiteSpace(outputFilePath);
+ public void Inflate(string inputFilePath, string outputFilePath)
+ {
+ ArgumentNullException.ThrowIfNullOrWhiteSpace(inputFilePath);
+ ArgumentNullException.ThrowIfNullOrWhiteSpace(outputFilePath);
- var inputStream = this.ReadFrequencyDictionary(inputFilePath);
- this.BuildTree();
- this.BuildBinaryCodeMappings();
- this.InflateInternal(inputStream, outputFilePath);
- }
+ var inputStream = this.ReadFrequencyDictionary(inputFilePath);
+ this.BuildTree();
+ this.BuildBinaryCodeMappings();
+ this.InflateInternal(inputStream, outputFilePath);
+ }
- private void InitializeFrequencyDictionary(string inputFilePath)
+ private void InitializeFrequencyDictionary(string inputFilePath)
+ {
+ this.frequencyCounter = new FrequencyCounter();
+ using (var inputStream = File.OpenRead(inputFilePath))
{
- this.frequencyCounter = new FrequencyCounter();
- using (var inputStream = File.OpenRead(inputFilePath))
+ int inputByte;
+ // -1 represents end of stream, otherwise byte cast as int
+ while ((inputByte = inputStream.ReadByte()) != -1)
{
- int inputByte;
- // -1 represents end of stream, otherwise byte cast as int
- while ((inputByte = inputStream.ReadByte()) != -1)
- {
- byte nativeByte = (byte)inputByte;
- this.frequencyCounter.Increment(nativeByte);
- }
+ byte nativeByte = (byte)inputByte;
+ this.frequencyCounter.Increment(nativeByte);
}
}
+ }
- private void BuildTree()
+ private void BuildTree()
+ {
+ // Use a MinHeap priority queue, creating a node with the byte, and the frequency as priority
+ var priorityQueue = new PriorityQueue, UInt32>();
+ foreach (var kvp in frequencyCounter.GetEnumerator())
{
- // Use a MinHeap priority queue, creating a node with the byte, and the frequency as priority
- var priorityQueue = new PriorityQueue, UInt32>();
- foreach (var kvp in frequencyCounter.GetEnumerator())
- {
- priorityQueue.Enqueue(new Node(kvp.Key), kvp.Value);
- }
-
- // Enque special "end of file" node with value -1 and priority 0. This special marker will appear at the end of the file so that during
- // decompression we deterministically know we have exhausted the input file. This allows us to compress arbitrarily large input files without having to save in
- // the file header the number of bytes in the input, which could overflow for very large files.
- priorityQueue.Enqueue(new Node(EndOfFileCode), 0);
+ priorityQueue.Enqueue(new Node(kvp.Key), kvp.Value);
+ }
- // Take the 2 nodes at the head of the queue (lowest frequency) and combine into a new node
- // The tree is complete when there is only 1 node left
- while (priorityQueue.Count > 1)
- {
- priorityQueue.TryDequeue(out var leftNode, out UInt32 leftPriority);
- priorityQueue.TryDequeue(out var rightNode, out UInt32 rightPriority);
- priorityQueue.Enqueue(new Node(leftNode!, rightNode!), leftPriority + rightPriority);
- }
+ // Enque special "end of file" node with value -1 and priority 0. This special marker will appear at the end of the file so that during
+ // decompression we deterministically know we have exhausted the input file. This allows us to compress arbitrarily large input files without having to save in
+ // the file header the number of bytes in the input, which could overflow for very large files.
+ priorityQueue.Enqueue(new Node(EndOfFileCode), 0);
- this.treeRoot = priorityQueue.Dequeue();
+ // Take the 2 nodes at the head of the queue (lowest frequency) and combine into a new node
+ // The tree is complete when there is only 1 node left
+ while (priorityQueue.Count > 1)
+ {
+ priorityQueue.TryDequeue(out var leftNode, out UInt32 leftPriority);
+ priorityQueue.TryDequeue(out var rightNode, out UInt32 rightPriority);
+ priorityQueue.Enqueue(new Node(leftNode!, rightNode!), leftPriority + rightPriority);
}
- private void BuildBinaryCodeMappings()
+ this.treeRoot = priorityQueue.Dequeue();
+ }
+
+ private void BuildBinaryCodeMappings()
+ {
+ this.binaryCodeMappings = new Dictionary();
+ BuildBinaryCodeMappings(this.treeRoot!, string.Empty);
+ }
+
+ private void BuildBinaryCodeMappings(Node node, string binaryCode)
+ {
+ if (node.IsLeafNode)
{
- this.binaryCodeMappings = new Dictionary();
- BuildBinaryCodeMappings(this.treeRoot!, string.Empty);
+ this.binaryCodeMappings!.Add(node.Value, binaryCode);
+ return;
}
- private void BuildBinaryCodeMappings(Node node, string binaryCode)
+ // Left node gets tagged with 0, right node gets tagged with 1
+ this.BuildBinaryCodeMappings(node.GetLeft()!, $"{binaryCode}0");
+ this.BuildBinaryCodeMappings(node.GetRight()!, $"{binaryCode}1");
+ }
+
+ private void CompressInternal(string inputFilePath, string outputFilePath)
+ {
+ using (var inputStream = File.OpenRead(inputFilePath))
{
- if (node.IsLeafNode)
+ // Open a filestream to the destination (compressed) file. If the file already exists, it will be overwritten.
+ using (var outputStream = new FileStream(outputFilePath, FileMode.Create, FileAccess.Write))
{
- this.binaryCodeMappings!.Add(node.Value, binaryCode);
- return;
- }
+ this.WriteFrequencyDictionary(outputStream);
- // Left node gets tagged with 0, right node gets tagged with 1
- this.BuildBinaryCodeMappings(node.GetLeft()!, $"{binaryCode}0");
- this.BuildBinaryCodeMappings(node.GetRight()!, $"{binaryCode}1");
- }
+ var bitWriter = new BitWriter(outputStream);
- private void CompressInternal(string inputFilePath, string outputFilePath)
- {
- using (var inputStream = File.OpenRead(inputFilePath))
- {
- // Open a filestream to the destination (compressed) file. If the file already exists, it will be overwritten.
- using (var outputStream = new FileStream(outputFilePath, FileMode.Create, FileAccess.Write))
+ // Main loop to encode each byte in the input stream according to its binary code mapping
+ int inputByte;
+ while ((inputByte = inputStream.ReadByte()) != -1)
{
- this.WriteFrequencyDictionary(outputStream);
+ bitWriter.WriteBits(this.binaryCodeMappings![(byte)inputByte]);
+ }
- var bitWriter = new BitWriter(outputStream);
+ // Write End of file code at the very end.
+ bitWriter.WriteBits(this.binaryCodeMappings![EndOfFileCode]);
- // Main loop to encode each byte in the input stream according to its binary code mapping
- int inputByte;
- while ((inputByte = inputStream.ReadByte()) != -1)
- {
- bitWriter.WriteBits(this.binaryCodeMappings![(byte)inputByte]);
- }
+ bitWriter.Flush();
+ }
+ }
+ }
- // Write End of file code at the very end.
- bitWriter.WriteBits(this.binaryCodeMappings![EndOfFileCode]);
+ ///
+ /// Writes the frequency dictionary to the output file so that the binary tree can be rebuilt to decompress the file.
+ /// As an optimization, we only write frequencies for the bytes that were present in the input file.
+ /// Note: storing the binary code mappings could be used as an alternate way to decode the file, but it would consume more disk space than the frequencies table
+ /// defeating the purpose of an efficient compression algorithm. Instead, the binary code mappings will be rebuilt at time of decompression from this frequency table.
+ ///
+ ///
+ private void WriteFrequencyDictionary(FileStream outputStream)
+ {
+ var writer = new BinaryWriter(outputStream);
- bitWriter.Flush();
- }
- }
+ // frequency table size can be 256 + 1 end of file character (257) at most, so we need 2 bytes at most (ushort) on the header of size of frequency table
+ writer.Write((ushort)this.frequencyCounter.GetEnumerator().Count());
+ foreach (var kvp in this.frequencyCounter.GetEnumerator())
+ {
+ writer.Write(kvp.Key);
+ writer.Write(kvp.Value);
}
+ writer.Flush();
+ }
- ///
- /// Writes the frequency dictionary to the output file so that the binary tree can be rebuilt to decompress the file.
- /// As an optimization, we only write frequencies for the bytes that were present in the input file.
- /// Note: storing the binary code mappings could be used as an alternate way to decode the file, but it would consume more disk space than the frequencies table
- /// defeating the purpose of an efficient compression algorithm. Instead, the binary code mappings will be rebuilt at time of decompression from this frequency table.
- ///
- ///
- private void WriteFrequencyDictionary(FileStream outputStream)
+ private FileStream ReadFrequencyDictionary(string inputFilePath)
+ {
+ this.frequencyCounter = new FrequencyCounter();
+ FileStream inputStream;
+ try
+ {
+ inputStream = File.OpenRead(inputFilePath);
+ }
+ catch (Exception e)
{
- var writer = new BinaryWriter(outputStream);
+ Console.WriteLine($"Exception opening input file: {e.Message}");
+ throw;
+ }
- // frequency table size can be 256 + 1 end of file character (257) at most, so we need 2 bytes at most (ushort) on the header of size of frequency table
- writer.Write((ushort)this.frequencyCounter.GetEnumerator().Count());
- foreach (var kvp in this.frequencyCounter.GetEnumerator())
- {
- writer.Write(kvp.Key);
- writer.Write(kvp.Value);
- }
- writer.Flush();
+ var reader = new BinaryReader(inputStream);
+ var frequencyTableSize = reader.ReadUInt16();
+ // 256 = all possible 8 bit characters
+ if (frequencyTableSize < 0 || frequencyTableSize > 256)
+ {
+ throw new ArgumentOutOfRangeException($"Invalid frequency count {frequencyTableSize} in input file");
}
- private FileStream ReadFrequencyDictionary(string inputFilePath)
+ for (int i = 0; i < frequencyTableSize; i++)
{
- this.frequencyCounter = new FrequencyCounter();
- FileStream inputStream;
- try
- {
- inputStream = File.OpenRead(inputFilePath);
- }
- catch (Exception e)
- {
- Console.WriteLine($"Exception opening input file: {e.Message}");
- throw;
- }
+ var key = reader.ReadByte();
+ var value = reader.ReadUInt32();
+ this.frequencyCounter.SetFrequency(key, value);
+ }
- var reader = new BinaryReader(inputStream);
- var frequencyTableSize = reader.ReadUInt16();
- // 256 = all possible 8 bit characters
- if (frequencyTableSize < 0 || frequencyTableSize > 256)
- {
- throw new ArgumentOutOfRangeException($"Invalid frequency count {frequencyTableSize} in input file");
- }
+ // Hand off the input stream to the next steps of decompression so they continue reading after the frequency dictionary header
+ return inputStream;
+ }
- for (int i = 0; i < frequencyTableSize; i++)
+ private void InflateInternal(FileStream inputStream, string outputFilePath)
+ {
+ // Open a filestream to the destination (uncompressed) file. If the file already exists, it will be overwritten.
+ using (var outputStream = new FileStream(outputFilePath, FileMode.Create, FileAccess.Write))
+ {
+ // Special case if input file was empty, nothing to do
+ if (this.frequencyCounter.GetEnumerator().Count() == 0)
{
- var key = reader.ReadByte();
- var value = reader.ReadUInt32();
- this.frequencyCounter.SetFrequency(key, value);
+ return;
}
- // Hand off the input stream to the next steps of decompression so they continue reading after the frequency dictionary header
- return inputStream;
- }
-
- private void InflateInternal(FileStream inputStream, string outputFilePath)
- {
- // Open a filestream to the destination (uncompressed) file. If the file already exists, it will be overwritten.
- using (var outputStream = new FileStream(outputFilePath, FileMode.Create, FileAccess.Write))
+ // For decompression, we key off binary codes to obtain the corresponding byte, which is the opposite to what we do in compression.
+ // This ensures that lookup for decompression has constant time complexity.
+ var reverseBinaryCodeMappings = this.binaryCodeMappings?.ToDictionary(kvp => kvp.Value, kvp => kvp.Key);
+ var bitReader = new BitReader(inputStream);
+ var endOfFileFound = false;
+ while (!endOfFileFound)
{
- // Special case if input file was empty, nothing to do
- if (this.frequencyCounter.GetEnumerator().Count() == 0)
+ var bitString = string.Empty;
+ var binaryCodeMatch = false;
+ while (!binaryCodeMatch)
{
- return;
- }
-
- // For decompression, we key off binary codes to obtain the corresponding byte, which is the opposite to what we do in compression.
- // This ensures that lookup for decompression has constant time complexity.
- var reverseBinaryCodeMappings = this.binaryCodeMappings?.ToDictionary(kvp => kvp.Value, kvp => kvp.Key);
- var bitReader = new BitReader(inputStream);
- var endOfFileFound = false;
- while (!endOfFileFound)
- {
- var bitString = string.Empty;
- var binaryCodeMatch = false;
- while (!binaryCodeMatch)
+ var bit = bitReader.ReadNextBit();
+ bitString = $"{bitString}{bit}";
+ if (reverseBinaryCodeMappings!.ContainsKey(bitString))
{
- var bit = bitReader.ReadNextBit();
- bitString = $"{bitString}{bit}";
- if (reverseBinaryCodeMappings!.ContainsKey(bitString))
+ binaryCodeMatch = true;
+ if (reverseBinaryCodeMappings![bitString] == EndOfFileCode)
+ {
+ endOfFileFound = true;
+ }
+ else
{
+ // A matching pattern in the binary code mappings is found, write the corresponding byte to the output
+ outputStream.WriteByte((byte)reverseBinaryCodeMappings[bitString]);
binaryCodeMatch = true;
- if (reverseBinaryCodeMappings![bitString] == EndOfFileCode)
- {
- endOfFileFound = true;
- }
- else
- {
- // A matching pattern in the binary code mappings is found, write the corresponding byte to the output
- outputStream.WriteByte((byte)reverseBinaryCodeMappings[bitString]);
- binaryCodeMatch = true;
- }
}
}
}
- inputStream.Close();
}
+ inputStream.Close();
}
}
}
\ No newline at end of file
diff --git a/HuffmanCompressor/IFileCompressor.cs b/HuffmanCompressor/IFileCompressor.cs
index d77d10d..018a86a 100644
--- a/HuffmanCompressor/IFileCompressor.cs
+++ b/HuffmanCompressor/IFileCompressor.cs
@@ -1,11 +1,10 @@
-namespace HuffmanCompressorLib
+namespace HuffmanCompressor.Lib;
+
+///
+/// Interface for file compression and decompression.
+///
+public interface IFileCompressor
{
- ///
- /// Interface for file compression and decompression.
- ///
- public interface IFileCompressor
- {
- void Compress(string inputFilePath, string outputFilePath);
- void Inflate(string inputFilePath, string outputFilePath);
- }
+ void Compress(string inputFilePath, string outputFilePath);
+ void Inflate(string inputFilePath, string outputFilePath);
}
diff --git a/HuffmanCompressor/Node.cs b/HuffmanCompressor/Node.cs
index 86850cc..1988637 100644
--- a/HuffmanCompressor/Node.cs
+++ b/HuffmanCompressor/Node.cs
@@ -1,75 +1,74 @@
-namespace HuffmanCompressorLib
+namespace HuffmanCompressor.Lib;
+
+///
+/// Represents a node in a binary tree.
+///
+/// Data type.
+internal class Node
{
+ private Node? left;
+ private Node? right;
+ private T? value;
+
///
- /// Represents a node in a binary tree.
+ /// Creates a new instance of class.
///
- /// Data type.
- internal class Node
+ /// Value of the node
+ public Node(T value)
{
- private Node? left;
- private Node? right;
- private T? value;
+ this.left = null;
+ this.right = null;
+ this.value = value;
+ }
- ///
- /// Creates a new instance of class.
- ///
- /// Value of the node
- public Node(T value)
- {
- this.left = null;
- this.right = null;
- this.value = value;
- }
+ ///
+ /// Creates a new instance of class.
+ ///
+ /// Left node.
+ /// Right node.
+ public Node(Node left, Node right)
+ {
+ this.left = left;
+ this.right = right;
+ }
- ///
- /// Creates a new instance of class.
- ///
- /// Left node.
- /// Right node.
- public Node(Node left, Node right)
- {
- this.left = left;
- this.right = right;
- }
+ ///
+ /// Gets the left node.
+ ///
+ /// Left node.
+ public Node? GetLeft()
+ {
+ return this.left;
+ }
- ///
- /// Gets the left node.
- ///
- /// Left node.
- public Node? GetLeft()
- {
- return this.left;
- }
+ ///
+ /// Gets the right node.
+ ///
+ /// Right node.
+ public Node? GetRight()
+ {
+ return this.right;
+ }
- ///
- /// Gets the right node.
- ///
- /// Right node.
- public Node? GetRight()
+ ///
+ /// Gets a value indicating whether the node is a leaf node.
+ ///
+ public bool IsLeafNode
+ {
+ get
{
- return this.right;
+ return left == null && right == null;
}
+ }
- ///
- /// Gets a value indicating whether the node is a leaf node.
- ///
- public bool IsLeafNode
+ ///
+ /// Gets the value of the node.
+ ///
+ public T? Value
+ {
+ get
{
- get
- {
- return left == null && right == null;
- }
+ return value;
}
-
- ///
- /// Gets the value of the node.
- ///
- public T? Value
- {
- get
- {
- return value;
- }
- }
- }
+ }
}
diff --git a/HuffmanCompressor/Properties/AssemblyInfo.cs b/HuffmanCompressor/Properties/AssemblyInfo.cs
index fc243c7..6aaa1e9 100644
--- a/HuffmanCompressor/Properties/AssemblyInfo.cs
+++ b/HuffmanCompressor/Properties/AssemblyInfo.cs
@@ -17,5 +17,5 @@
[assembly: Guid("5c38fdf8-890d-4727-aeb6-52085e532832")]
-[assembly: InternalsVisibleTo("HuffmanCompressorTests")]
+[assembly: InternalsVisibleTo("HuffmanCompressor.Tests")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
diff --git a/HuffmanCompressorCmd/AssemblyInfo.cs b/HuffmanCompressorCmd/AssemblyInfo.cs
index 87a6d0f..26d78a2 100644
--- a/HuffmanCompressorCmd/AssemblyInfo.cs
+++ b/HuffmanCompressorCmd/AssemblyInfo.cs
@@ -17,5 +17,5 @@
[assembly: Guid("29445467-fd04-458f-9bd4-fcd842b0468d")]
-[assembly: InternalsVisibleTo("HuffmanCompressorTests")]
+[assembly: InternalsVisibleTo("HuffmanCompressor.Tests")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
diff --git a/HuffmanCompressorCmd/HuffmanCompressorCmd.csproj b/HuffmanCompressorCmd/HuffmanCompressor.Cmd.csproj
similarity index 94%
rename from HuffmanCompressorCmd/HuffmanCompressorCmd.csproj
rename to HuffmanCompressorCmd/HuffmanCompressor.Cmd.csproj
index d1a7347..372a954 100644
--- a/HuffmanCompressorCmd/HuffmanCompressorCmd.csproj
+++ b/HuffmanCompressorCmd/HuffmanCompressor.Cmd.csproj
@@ -8,7 +8,7 @@
-
+
diff --git a/HuffmanCompressorCmd/Program.cs b/HuffmanCompressorCmd/Program.cs
index 1f8101e..a95fc6f 100644
--- a/HuffmanCompressorCmd/Program.cs
+++ b/HuffmanCompressorCmd/Program.cs
@@ -1,73 +1,71 @@
-namespace HuffmanCompressorCmd
+namespace HuffmanCompressor.Cmd;
+using HuffmanCompressor.Lib;
+
+///
+/// Main entry point for the HuffmanCompressorCmd console application.
+///
+public class Program
{
- using HuffmanCompressorLib;
+ private IFileCompressor _compressor;
///
- /// Main entry point for the HuffmanCompressorCmd console application.
+ /// Constructor of the Program class.
///
- public class Program
+ public Program()
{
- private IFileCompressor _compressor;
+ _compressor = new HuffmanCompressor();
+ }
- ///
- /// Constructor of the Program class.
- ///
- public Program()
- {
- _compressor = new HuffmanCompressor();
- }
+ ///
+ /// Internal method intended for the unit tests to be able to inject a mock interface for testing purposes.
+ ///
+ /// Instance of the compressor interface.
+ internal void SetCompressorReference(IFileCompressor compressor)
+ {
+ _compressor = compressor;
+ }
+
+ ///
+ /// The main entry point (Main method) for the application always needs to be declared as static.
+ /// That means that it cannot access non-static members of the class, such as _compressor.
+ /// Declaring the _compressor member as static would create a single instance of the compressor for all instances of the Program class.
+ /// This would be a problem if the Program class was used in a multi-threaded environment, such as when unit tests are run, where we
+ /// may run parallel compression jobs or even want to inject a mock compressor for testing purposes.
+ /// To avoid this, we create the Run wrapper as non-static and have Main create an instance of the Program class to invoke it.
+ ///
+ /// Program args
+ ///
+ public void Run(string[] args)
+ {
+ const string usageString = "Usage: [compress|inflate] [input file path] [output file path]";
- ///
- /// Internal method intended for the unit tests to be able to inject a mock interface for testing purposes.
- ///
- /// Instance of the compressor interface.
- internal void SetCompressorReference(IFileCompressor compressor)
+ if (args.Length != 3)
{
- _compressor = compressor;
+ Console.WriteLine(usageString);
+ throw new ArgumentException(usageString);
}
- ///
- /// The main entry point (Main method) for the application always needs to be declared as static.
- /// That means that it cannot access non-static members of the class, such as _compressor.
- /// Declaring the _compressor member as static would create a single instance of the compressor for all instances of the Program class.
- /// This would be a problem if the Program class was used in a multi-threaded environment, such as when unit tests are run, where we
- /// may run parallel compression jobs or even want to inject a mock compressor for testing purposes.
- /// To avoid this, we create the Run wrapper as non-static and have Main create an instance of the Program class to invoke it.
- ///
- /// Program args
- ///
- public void Run(string[] args)
+ switch (args[0].ToLower())
{
- const string usageString = "Usage: [compress|inflate] [input file path] [output file path]";
-
- if (args.Length != 3)
- {
+ case "compress":
+ _compressor.Compress(args[1], args[2]);
+ break;
+ case "inflate":
+ _compressor.Inflate(args[1], args[2]);
+ break;
+ default:
Console.WriteLine(usageString);
throw new ArgumentException(usageString);
- }
-
- switch (args[0].ToLower())
- {
- case "compress":
- _compressor.Compress(args[1], args[2]);
- break;
- case "inflate":
- _compressor.Inflate(args[1], args[2]);
- break;
- default:
- Console.WriteLine(usageString);
- throw new ArgumentException(usageString);
- }
}
+ }
- ///
- /// Main entry point for the HuffmanCompressorCmd console application.
- ///
- /// Program arguments.
- public static void Main(string[] args)
- {
- var program = new Program();
- program.Run(args);
- }
+ ///
+ /// Main entry point for the HuffmanCompressorCmd console application.
+ ///
+ /// Program arguments.
+ public static void Main(string[] args)
+ {
+ var program = new Program();
+ program.Run(args);
}
}
\ No newline at end of file
diff --git a/HuffmanCompressorTests/EndToEndTests.cs b/HuffmanCompressorTests/EndToEndTests.cs
index bb31a37..e93f14a 100644
--- a/HuffmanCompressorTests/EndToEndTests.cs
+++ b/HuffmanCompressorTests/EndToEndTests.cs
@@ -1,49 +1,47 @@
-namespace HuffmanCompressorTests
-{
- using HuffmanCompressorCmd;
+using HuffmanCompressor.Cmd;
+namespace HuffmanCompressor.Tests;
- public class EndToEndTests
+public class EndToEndTests
+{
+ [Theory]
+ [InlineData("E2E-SmallFile.txt", true)]
+ [InlineData("E2E-EmptyFile.txt", false)]
+ [InlineData("E2E-SingleCharacter.txt", false)]
+ [InlineData("E2E-WordFile.docx", false)]
+ public void CompressTest(string fileName, bool verifySmallerCompressedFileSize)
{
- [Theory]
- [InlineData("E2E-SmallFile.txt", true)]
- [InlineData("E2E-EmptyFile.txt", false)]
- [InlineData("E2E-SingleCharacter.txt", false)]
- [InlineData("E2E-WordFile.docx", false)]
- public void CompressTest(string fileName, bool verifySmallerCompressedFileSize)
- {
- // Arrange
- // Note: Use unique output file name to ensure no collision if tests run in parallel.
- var inputFilePath = Utilities.GetTestPath(fileName);
- var compressedFilePath = Utilities.GetTestPath(fileName + ".huf");
- var inflatedFilePath = Utilities.GetTestPath(inputFilePath + ".inf");
+ // Arrange
+ // Note: Use unique output file name to ensure no collision if tests run in parallel.
+ var inputFilePath = Utilities.GetTestPath(fileName);
+ var compressedFilePath = Utilities.GetTestPath(fileName + ".huf");
+ var inflatedFilePath = Utilities.GetTestPath(inputFilePath + ".inf");
- // Act
- Program.Main(["compress", inputFilePath, compressedFilePath]);
+ // Act
+ Program.Main(["compress", inputFilePath, compressedFilePath]);
- // Assert
- Assert.True(File.Exists(compressedFilePath));
+ // Assert
+ Assert.True(File.Exists(compressedFilePath));
- // Verify the compression produced a file smaller in size.
- // Note: The compressed file includes the overhead of the character frequency table
- // this means that there is a threshold for which compression will not be effective.
- // Also, files that are already compressed, such as zip files or docx files have high entropy and will not compress further
- FileInfo inputFileInfo, compressedFileInfo, inflatedFileInfo;
- inputFileInfo = new FileInfo(inputFilePath);
- compressedFileInfo = new FileInfo(compressedFilePath);
- if (verifySmallerCompressedFileSize)
- {
- Assert.True(inputFileInfo.Length > compressedFileInfo.Length);
- }
+ // Verify the compression produced a file smaller in size.
+ // Note: The compressed file includes the overhead of the character frequency table
+ // this means that there is a threshold for which compression will not be effective.
+ // Also, files that are already compressed, such as zip files or docx files have high entropy and will not compress further
+ FileInfo inputFileInfo, compressedFileInfo, inflatedFileInfo;
+ inputFileInfo = new FileInfo(inputFilePath);
+ compressedFileInfo = new FileInfo(compressedFilePath);
+ if (verifySmallerCompressedFileSize)
+ {
+ Assert.True(inputFileInfo.Length > compressedFileInfo.Length);
+ }
- // Act
- Program.Main(["inflate", compressedFilePath, inflatedFilePath]);
- inflatedFileInfo = new FileInfo(inflatedFilePath);
+ // Act
+ Program.Main(["inflate", compressedFilePath, inflatedFilePath]);
+ inflatedFileInfo = new FileInfo(inflatedFilePath);
- // Assert
- Assert.Equal(inputFileInfo.Length, inflatedFileInfo.Length);
- var originalHash = Utilities.GetFileHash(fileName);
- var inflatedHash = Utilities.GetFileHash(inflatedFilePath);
- Assert.Equal(originalHash, inflatedHash);
- }
+ // Assert
+ Assert.Equal(inputFileInfo.Length, inflatedFileInfo.Length);
+ var originalHash = Utilities.GetFileHash(fileName);
+ var inflatedHash = Utilities.GetFileHash(inflatedFilePath);
+ Assert.Equal(originalHash, inflatedHash);
}
}
diff --git a/HuffmanCompressorTests/FrequencyCounterTests.cs b/HuffmanCompressorTests/FrequencyCounterTests.cs
index 02d9736..bf5be3f 100644
--- a/HuffmanCompressorTests/FrequencyCounterTests.cs
+++ b/HuffmanCompressorTests/FrequencyCounterTests.cs
@@ -1,75 +1,73 @@
-namespace HuffmanCompressorTests
-{
- using HuffmanCompressorLib;
+using HuffmanCompressor.Lib;
+namespace HuffmanCompressor.Tests;
- public class FrequencyCounterTests
+public class FrequencyCounterTests
+{
+ [Fact]
+ public void AddItemTest()
{
- [Fact]
- public void AddItemTest()
- {
- // Arrange
- var counter = new FrequencyCounter();
+ // Arrange
+ var counter = new FrequencyCounter();
- // Act
- counter.Increment((byte)'a');
+ // Act
+ counter.Increment((byte)'a');
- // Assert
- Assert.Equal((UInt32)1, counter.GetFrequency((byte)'a'));
- Assert.Equal((UInt32)0, counter.GetFrequency((byte)'b'));
- }
+ // Assert
+ Assert.Equal((UInt32)1, counter.GetFrequency((byte)'a'));
+ Assert.Equal((UInt32)0, counter.GetFrequency((byte)'b'));
+ }
- [Fact]
- public void SetFrequencyTest()
- {
- // Arrange
- var counter = new FrequencyCounter();
+ [Fact]
+ public void SetFrequencyTest()
+ {
+ // Arrange
+ var counter = new FrequencyCounter();
- // Act
- counter.SetFrequency((byte)'a',23);
+ // Act
+ counter.SetFrequency((byte)'a',23);
- // Assert
- Assert.Equal((UInt32)23, counter.GetFrequency((byte)'a'));
- Assert.Equal((UInt32)0, counter.GetFrequency((byte)'b'));
- }
+ // Assert
+ Assert.Equal((UInt32)23, counter.GetFrequency((byte)'a'));
+ Assert.Equal((UInt32)0, counter.GetFrequency((byte)'b'));
+ }
- [Fact]
- public void GetEnumeratorTest()
- {
- // Arrange
- var counter = new FrequencyCounter();
+ [Fact]
+ public void GetEnumeratorTest()
+ {
+ // Arrange
+ var counter = new FrequencyCounter();
- // Act
- counter.SetFrequency((byte)'a', 23);
+ // Act
+ counter.SetFrequency((byte)'a', 23);
- // Assert
- Assert.Single(counter.GetEnumerator());
- foreach ( var kvp in counter.GetEnumerator())
- {
- Assert.Equal((byte)'a', kvp.Key);
- Assert.Equal((UInt32)23, kvp.Value);
- }
+ // Assert
+ Assert.Single(counter.GetEnumerator());
+ foreach ( var kvp in counter.GetEnumerator())
+ {
+ Assert.Equal((byte)'a', kvp.Key);
+ Assert.Equal((UInt32)23, kvp.Value);
}
+ }
- [Fact]
- public void IncrementOverflowTest()
- {
- // Arrange
- var counter = new FrequencyCounter();
+ [Fact]
+ public void IncrementOverflowTest()
+ {
+ // Arrange
+ var counter = new FrequencyCounter();
- // Act
- counter.SetFrequency((byte)'a', UInt32.MaxValue);
+ // Act
+ counter.SetFrequency((byte)'a', UInt32.MaxValue);
- // Assert
- Assert.Single(counter.GetEnumerator());
- Assert.Equal(UInt32.MaxValue, counter.GetFrequency((byte)'a'));
+ // Assert
+ Assert.Single(counter.GetEnumerator());
+ Assert.Equal(UInt32.MaxValue, counter.GetFrequency((byte)'a'));
- // Act
- counter.Increment((byte)'a');
+ // Act
+ counter.Increment((byte)'a');
- // We don't check for a specific value, we allow the counter to use it's own method of rebasing the count,
- // just ensure it didn't wrap back to 0
- Assert.True(counter.GetFrequency((byte)'a') > 0);
+ // We don't check for a specific value, we allow the counter to use it's own method of rebasing the count,
+ // just ensure it didn't wrap back to 0
+ Assert.True(counter.GetFrequency((byte)'a') > 0);
- }
}
}
diff --git a/HuffmanCompressorTests/HuffmanCompressorTests.csproj b/HuffmanCompressorTests/HuffmanCompressor.Tests.csproj
similarity index 97%
rename from HuffmanCompressorTests/HuffmanCompressorTests.csproj
rename to HuffmanCompressorTests/HuffmanCompressor.Tests.csproj
index 5d81aa9..2e50fdf 100644
--- a/HuffmanCompressorTests/HuffmanCompressorTests.csproj
+++ b/HuffmanCompressorTests/HuffmanCompressor.Tests.csproj
@@ -19,8 +19,8 @@
-
-
+
+
diff --git a/HuffmanCompressorTests/HuffmanCompressorTests.cs b/HuffmanCompressorTests/HuffmanCompressorTests.cs
index ecc36b0..a8fbff5 100644
--- a/HuffmanCompressorTests/HuffmanCompressorTests.cs
+++ b/HuffmanCompressorTests/HuffmanCompressorTests.cs
@@ -1,93 +1,91 @@
-namespace HuffmanCompressorTests
+namespace HuffmanCompressor.Tests;
+using HuffmanCompressor.Lib;
+
+public class HuffmanCompressorTests
{
- using HuffmanCompressorLib;
+ private const string TestDataFolderName = "TestData";
+
+ [Fact]
+ public void ConstructorTest()
+ {
+ // Arrange & Act
+ var compressor = new HuffmanCompressor();
+
+ // Assert
+ Assert.NotNull(compressor);
+ }
+
+ [Fact]
+ public void CompressThrowsExceptionForWhitespaceInputFileName()
+ {
+ // Arrange
+ var compressor = new HuffmanCompressor();
- public class HuffmanCompressorTests
+ // Act & Assert
+ Assert.Throws(() => compressor.Compress(string.Empty, "outputFile.bin"));
+ }
+
+ [Fact]
+ public void CompressThrowsExceptionForWhitespaceOutputFileName()
{
- private const string TestDataFolderName = "TestData";
-
- [Fact]
- public void ConstructorTest()
- {
- // Arrange & Act
- var compressor = new HuffmanCompressor();
-
- // Assert
- Assert.NotNull(compressor);
- }
-
- [Fact]
- public void CompressThrowsExceptionForWhitespaceInputFileName()
- {
- // Arrange
- var compressor = new HuffmanCompressor();
-
- // Act & Assert
- Assert.Throws(() => compressor.Compress(string.Empty, "outputFile.bin"));
- }
-
- [Fact]
- public void CompressThrowsExceptionForWhitespaceOutputFileName()
- {
- // Arrange
- var compressor = new HuffmanCompressor();
-
- // Act & Assert
- Assert.Throws(() => compressor.Compress("inputFile.txt", string.Empty));
- }
-
- [Fact]
- public void InflateThrowsExceptionForWhitespaceInputFileName()
- {
- // Arrange
- var compressor = new HuffmanCompressor();
-
- // Act & Assert
- Assert.Throws(() => compressor.Inflate(string.Empty, "outputFile.bin"));
- }
-
- [Fact]
- public void InflateThrowsExceptionForWhitespaceOutputFileName()
- {
- // Arrange
- var compressor = new HuffmanCompressor();
-
- // Act & Assert
- Assert.Throws(() => compressor.Inflate("inputFile.huf", string.Empty));
- }
-
- [Theory]
- [InlineData("Smallfile.txt")]
- [InlineData("Emptyfile.txt")]
- [InlineData("SingleCharacter.txt")]
- [InlineData("WordFile.docx")]
- public void CompressAndInflateTest(string fileName)
- {
- // Arrange
- var inputFilePath = Utilities.GetTestPath(fileName);
- var compressedFilePath = Utilities.GetTestPath(fileName + ".huf");
- var inflatedFilePath = Utilities.GetTestPath(compressedFilePath + ".inf");
-
- var compressor = new HuffmanCompressor();
-
- // Act
- compressor.Compress(inputFilePath, compressedFilePath);
-
- // Assert
- Assert.True(File.Exists(compressedFilePath));
-
- // Act
- compressor.Inflate(compressedFilePath, inflatedFilePath);
-
- // Assert
- Assert.True(File.Exists(inflatedFilePath));
- var inputFileInfo = new FileInfo(inputFilePath);
- var inflatedFileInfo = new FileInfo(inflatedFilePath);
- Assert.Equal(inputFileInfo.Length, inflatedFileInfo.Length);
-
- var originalHash = Utilities.GetFileHash(fileName);
- var inflatedHash = Utilities.GetFileHash(inflatedFilePath);
- Assert.Equal(originalHash, inflatedHash);
- }
+ // Arrange
+ var compressor = new HuffmanCompressor();
+
+ // Act & Assert
+ Assert.Throws(() => compressor.Compress("inputFile.txt", string.Empty));
+ }
+
+ [Fact]
+ public void InflateThrowsExceptionForWhitespaceInputFileName()
+ {
+ // Arrange
+ var compressor = new HuffmanCompressor();
+
+ // Act & Assert
+ Assert.Throws(() => compressor.Inflate(string.Empty, "outputFile.bin"));
+ }
+
+ [Fact]
+ public void InflateThrowsExceptionForWhitespaceOutputFileName()
+ {
+ // Arrange
+ var compressor = new HuffmanCompressor();
+
+ // Act & Assert
+ Assert.Throws(() => compressor.Inflate("inputFile.huf", string.Empty));
+ }
+
+ [Theory]
+ [InlineData("Smallfile.txt")]
+ [InlineData("Emptyfile.txt")]
+ [InlineData("SingleCharacter.txt")]
+ [InlineData("WordFile.docx")]
+ public void CompressAndInflateTest(string fileName)
+ {
+ // Arrange
+ var inputFilePath = Utilities.GetTestPath(fileName);
+ var compressedFilePath = Utilities.GetTestPath(fileName + ".huf");
+ var inflatedFilePath = Utilities.GetTestPath(compressedFilePath + ".inf");
+
+ var compressor = new HuffmanCompressor();
+
+ // Act
+ compressor.Compress(inputFilePath, compressedFilePath);
+
+ // Assert
+ Assert.True(File.Exists(compressedFilePath));
+
+ // Act
+ compressor.Inflate(compressedFilePath, inflatedFilePath);
+
+ // Assert
+ Assert.True(File.Exists(inflatedFilePath));
+ var inputFileInfo = new FileInfo(inputFilePath);
+ var inflatedFileInfo = new FileInfo(inflatedFilePath);
+ Assert.Equal(inputFileInfo.Length, inflatedFileInfo.Length);
+
+ var originalHash = Utilities.GetFileHash(fileName);
+ var inflatedHash = Utilities.GetFileHash(inflatedFilePath);
+ Assert.Equal(originalHash, inflatedHash);
}
}
diff --git a/HuffmanCompressorTests/ProgramTests.cs b/HuffmanCompressorTests/ProgramTests.cs
index 009b2df..c6aea10 100644
--- a/HuffmanCompressorTests/ProgramTests.cs
+++ b/HuffmanCompressorTests/ProgramTests.cs
@@ -1,75 +1,73 @@
-namespace HuffmanCompressorTests
-{
- using HuffmanCompressorCmd;
- using HuffmanCompressorLib;
- using Moq;
+namespace HuffmanCompressor.Tests;
+using HuffmanCompressor.Cmd;
+using HuffmanCompressor.Lib;
+using Moq;
- public class ProgramTests
+public class ProgramTests
+{
+ [Fact]
+ public void CompressMethodInvokedWithCompressParameterTest()
{
- [Fact]
- public void CompressMethodInvokedWithCompressParameterTest()
- {
- // Arrange
- var mockCompressor = new Mock(MockBehavior.Strict);
- mockCompressor.Setup(c => c.Compress(It.IsAny(), It.IsAny()));
- var program = new Program();
- program.SetCompressorReference(mockCompressor.Object);
+ // Arrange
+ var mockCompressor = new Mock(MockBehavior.Strict);
+ mockCompressor.Setup(c => c.Compress(It.IsAny(), It.IsAny()));
+ var program = new Program();
+ program.SetCompressorReference(mockCompressor.Object);
- // Act
- program.Run(["compress", "input.txt", "output.bin" ]);
+ // Act
+ program.Run(["compress", "input.txt", "output.bin" ]);
- // Assert
- mockCompressor.Verify(compressor => compressor.Compress(
- It.Is(s => s.Equals("input.txt")),
- It.Is(s => s.Equals("output.bin"))),
- "Expected input or output paths not found");
- }
+ // Assert
+ mockCompressor.Verify(compressor => compressor.Compress(
+ It.Is(s => s.Equals("input.txt")),
+ It.Is(s => s.Equals("output.bin"))),
+ "Expected input or output paths not found");
+ }
- [Fact]
- public void InflateMethodInvokedWithCompressParameterTest()
- {
- // Arrange
- var mockCompressor = new Mock(MockBehavior.Strict);
- mockCompressor.Setup(c => c.Inflate(It.IsAny(), It.IsAny()));
- var program = new Program();
- program.SetCompressorReference(mockCompressor.Object);
+ [Fact]
+ public void InflateMethodInvokedWithCompressParameterTest()
+ {
+ // Arrange
+ var mockCompressor = new Mock(MockBehavior.Strict);
+ mockCompressor.Setup(c => c.Inflate(It.IsAny(), It.IsAny()));
+ var program = new Program();
+ program.SetCompressorReference(mockCompressor.Object);
- // Act
- program.Run(["inflate", "input.bin", "output.txt"]);
+ // Act
+ program.Run(["inflate", "input.bin", "output.txt"]);
- // Assert
- mockCompressor.Verify(compressor => compressor.Inflate(
- It.Is(s => s.Equals("input.bin")),
- It.Is(s => s.Equals("output.txt"))),
- "Expected input or output paths not found");
- }
+ // Assert
+ mockCompressor.Verify(compressor => compressor.Inflate(
+ It.Is(s => s.Equals("input.bin")),
+ It.Is(s => s.Equals("output.txt"))),
+ "Expected input or output paths not found");
+ }
- [Fact]
- public void ArgumentExceptionThrownWithInvalidCommandTest()
- {
- // Arrange
- var mockCompressor = new Mock(MockBehavior.Strict);
- var program = new Program();
- program.SetCompressorReference(mockCompressor.Object);
+ [Fact]
+ public void ArgumentExceptionThrownWithInvalidCommandTest()
+ {
+ // Arrange
+ var mockCompressor = new Mock(MockBehavior.Strict);
+ var program = new Program();
+ program.SetCompressorReference(mockCompressor.Object);
- // Act & Assert
- Assert.Throws(
- () => program.Run(["foo", "input.txt", "output.bin"]));
- }
+ // Act & Assert
+ Assert.Throws(
+ () => program.Run(["foo", "input.txt", "output.bin"]));
+ }
- [Theory]
- [InlineData("compress")]
- [InlineData("foo")]
- public void ArgumentExceptionThrownWithInvalidNumberOfParametersTest(string command)
- {
- // Arrange
- var mockCompressor = new Mock(MockBehavior.Strict);
- var program = new Program();
- program.SetCompressorReference(mockCompressor.Object);
+ [Theory]
+ [InlineData("compress")]
+ [InlineData("foo")]
+ public void ArgumentExceptionThrownWithInvalidNumberOfParametersTest(string command)
+ {
+ // Arrange
+ var mockCompressor = new Mock(MockBehavior.Strict);
+ var program = new Program();
+ program.SetCompressorReference(mockCompressor.Object);
- // Act & Assert
- Assert.Throws(
- () => program.Run([command]));
- }
+ // Act & Assert
+ Assert.Throws(
+ () => program.Run([command]));
}
}
\ No newline at end of file
diff --git a/HuffmanCompressorTests/Utilities.cs b/HuffmanCompressorTests/Utilities.cs
index 710e282..2762a7a 100644
--- a/HuffmanCompressorTests/Utilities.cs
+++ b/HuffmanCompressorTests/Utilities.cs
@@ -1,29 +1,27 @@
-namespace HuffmanCompressorTests
+namespace HuffmanCompressor.Tests;
+using System.IO.Hashing;
+using System.Reflection;
+using System.Text;
+
+public static class Utilities
{
- using System.IO.Hashing;
- using System.Reflection;
- using System.Text;
+ public const string TestDataFolderName = "TestData";
- public static class Utilities
+ public static string GetTestPath(string relativePath)
{
- public const string TestDataFolderName = "TestData";
-
- public static string GetTestPath(string relativePath)
- {
- var codeBaseUrl = new Uri(Assembly.GetExecutingAssembly().Location);
- var codeBasePath = Uri.UnescapeDataString(codeBaseUrl.AbsolutePath);
- var dirPath = Path.GetDirectoryName(codeBasePath);
- return Path.Combine(dirPath!, TestDataFolderName, relativePath);
- }
+ var codeBaseUrl = new Uri(Assembly.GetExecutingAssembly().Location);
+ var codeBasePath = Uri.UnescapeDataString(codeBaseUrl.AbsolutePath);
+ var dirPath = Path.GetDirectoryName(codeBasePath);
+ return Path.Combine(dirPath!, TestDataFolderName, relativePath);
+ }
- public static string GetFileHash(string fileName)
+ public static string GetFileHash(string fileName)
+ {
+ using (FileStream fileStream = File.OpenRead(GetTestPath(fileName)))
{
- using (FileStream fileStream = File.OpenRead(GetTestPath(fileName)))
- {
- var crc32 = new Crc32();
- crc32.Append(fileStream);
- return Encoding.UTF8.GetString(crc32.GetCurrentHash());
- }
+ var crc32 = new Crc32();
+ crc32.Append(fileStream);
+ return Encoding.UTF8.GetString(crc32.GetCurrentHash());
}
}
}
diff --git a/HufmannCompressorWinFormsApp/HuffmanCompressorWinFormsApp.csproj b/HufmannCompressorWinFormsApp/HuffmanCompressor.WinFormsApp.csproj
similarity index 94%
rename from HufmannCompressorWinFormsApp/HuffmanCompressorWinFormsApp.csproj
rename to HufmannCompressorWinFormsApp/HuffmanCompressor.WinFormsApp.csproj
index 0dc5b33..7b72cf3 100644
--- a/HufmannCompressorWinFormsApp/HuffmanCompressorWinFormsApp.csproj
+++ b/HufmannCompressorWinFormsApp/HuffmanCompressor.WinFormsApp.csproj
@@ -9,7 +9,7 @@
-
+
\ No newline at end of file
diff --git a/HufmannCompressorWinFormsApp/MainForm.Designer.cs b/HufmannCompressorWinFormsApp/MainForm.Designer.cs
index c7a810e..2657bf4 100644
--- a/HufmannCompressorWinFormsApp/MainForm.Designer.cs
+++ b/HufmannCompressorWinFormsApp/MainForm.Designer.cs
@@ -1,110 +1,108 @@
-namespace HufmannCompressorWinFormsApp
+namespace HufmannCompressor.WinFormsApp;
+partial class MainForm
{
- partial class MainForm
- {
- ///
- /// Required designer variable.
- ///
- private System.ComponentModel.IContainer components = null;
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
- ///
- /// Clean up any resources being used.
- ///
- /// true if managed resources should be disposed; otherwise, false.
- protected override void Dispose(bool disposing)
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
{
- if (disposing && (components != null))
- {
- components.Dispose();
- }
- base.Dispose(disposing);
+ components.Dispose();
}
+ base.Dispose(disposing);
+ }
- #region Windows Form Designer generated code
+ #region Windows Form Designer generated code
- ///
- /// Required method for Designer support - do not modify
- /// the contents of this method with the code editor.
- ///
- private void InitializeComponent()
- {
- btnCompressFile = new Button();
- openFileDialog = new OpenFileDialog();
- statusStrip = new StatusStrip();
- toolStripStatusLabel = new ToolStripStatusLabel();
- toolStripProgressBar1 = new ToolStripProgressBar();
- btnInflateFile = new Button();
- statusStrip.SuspendLayout();
- SuspendLayout();
- //
- // btnCompressFile
- //
- btnCompressFile.Location = new Point(38, 44);
- btnCompressFile.Margin = new Padding(2);
- btnCompressFile.Name = "btnCompressFile";
- btnCompressFile.Size = new Size(152, 36);
- btnCompressFile.TabIndex = 0;
- btnCompressFile.Text = "Compress file";
- btnCompressFile.UseVisualStyleBackColor = true;
- btnCompressFile.Click += btnCompressFile_Click;
- //
- // statusStrip
- //
- statusStrip.ImageScalingSize = new Size(24, 24);
- statusStrip.Items.AddRange(new ToolStripItem[] { toolStripStatusLabel, toolStripProgressBar1 });
- statusStrip.Location = new Point(0, 320);
- statusStrip.Name = "statusStrip";
- statusStrip.Size = new Size(615, 32);
- statusStrip.TabIndex = 1;
- statusStrip.Text = "statusStrip";
- //
- // toolStripStatusLabel
- //
- toolStripStatusLabel.Name = "toolStripStatusLabel";
- toolStripStatusLabel.Size = new Size(60, 25);
- toolStripStatusLabel.Text = "Ready";
- //
- // toolStripProgressBar1
- //
- toolStripProgressBar1.Name = "toolStripProgressBar1";
- toolStripProgressBar1.Size = new Size(200, 24);
- //
- // btnInflateFile
- //
- btnInflateFile.Location = new Point(222, 44);
- btnInflateFile.Margin = new Padding(2);
- btnInflateFile.Name = "btnInflateFile";
- btnInflateFile.Size = new Size(152, 36);
- btnInflateFile.TabIndex = 2;
- btnInflateFile.Text = "Inflate file";
- btnInflateFile.UseVisualStyleBackColor = true;
- btnInflateFile.Click += btnInflateFile_Click;
- //
- // MainForm
- //
- AutoScaleDimensions = new SizeF(10F, 25F);
- AutoScaleMode = AutoScaleMode.Font;
- ClientSize = new Size(615, 352);
- Controls.Add(btnInflateFile);
- Controls.Add(statusStrip);
- Controls.Add(btnCompressFile);
- Margin = new Padding(2);
- Name = "MainForm";
- Text = "Huffman Compressor";
- statusStrip.ResumeLayout(false);
- statusStrip.PerformLayout();
- ResumeLayout(false);
- PerformLayout();
- }
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ btnCompressFile = new Button();
+ openFileDialog = new OpenFileDialog();
+ statusStrip = new StatusStrip();
+ toolStripStatusLabel = new ToolStripStatusLabel();
+ toolStripProgressBar1 = new ToolStripProgressBar();
+ btnInflateFile = new Button();
+ statusStrip.SuspendLayout();
+ SuspendLayout();
+ //
+ // btnCompressFile
+ //
+ btnCompressFile.Location = new Point(38, 44);
+ btnCompressFile.Margin = new Padding(2);
+ btnCompressFile.Name = "btnCompressFile";
+ btnCompressFile.Size = new Size(152, 36);
+ btnCompressFile.TabIndex = 0;
+ btnCompressFile.Text = "Compress file";
+ btnCompressFile.UseVisualStyleBackColor = true;
+ btnCompressFile.Click += btnCompressFile_Click;
+ //
+ // statusStrip
+ //
+ statusStrip.ImageScalingSize = new Size(24, 24);
+ statusStrip.Items.AddRange(new ToolStripItem[] { toolStripStatusLabel, toolStripProgressBar1 });
+ statusStrip.Location = new Point(0, 320);
+ statusStrip.Name = "statusStrip";
+ statusStrip.Size = new Size(615, 32);
+ statusStrip.TabIndex = 1;
+ statusStrip.Text = "statusStrip";
+ //
+ // toolStripStatusLabel
+ //
+ toolStripStatusLabel.Name = "toolStripStatusLabel";
+ toolStripStatusLabel.Size = new Size(60, 25);
+ toolStripStatusLabel.Text = "Ready";
+ //
+ // toolStripProgressBar1
+ //
+ toolStripProgressBar1.Name = "toolStripProgressBar1";
+ toolStripProgressBar1.Size = new Size(200, 24);
+ //
+ // btnInflateFile
+ //
+ btnInflateFile.Location = new Point(222, 44);
+ btnInflateFile.Margin = new Padding(2);
+ btnInflateFile.Name = "btnInflateFile";
+ btnInflateFile.Size = new Size(152, 36);
+ btnInflateFile.TabIndex = 2;
+ btnInflateFile.Text = "Inflate file";
+ btnInflateFile.UseVisualStyleBackColor = true;
+ btnInflateFile.Click += btnInflateFile_Click;
+ //
+ // MainForm
+ //
+ AutoScaleDimensions = new SizeF(10F, 25F);
+ AutoScaleMode = AutoScaleMode.Font;
+ ClientSize = new Size(615, 352);
+ Controls.Add(btnInflateFile);
+ Controls.Add(statusStrip);
+ Controls.Add(btnCompressFile);
+ Margin = new Padding(2);
+ Name = "MainForm";
+ Text = "Huffman Compressor";
+ statusStrip.ResumeLayout(false);
+ statusStrip.PerformLayout();
+ ResumeLayout(false);
+ PerformLayout();
+ }
- #endregion
+ #endregion
- private Button btnCompressFile;
- private OpenFileDialog openFileDialog;
- private StatusStrip statusStrip;
- private ToolStripStatusLabel toolStripStatusLabel;
- private ToolStripProgressBar toolStripProgressBar1;
- private Button btnInflateFile;
- }
+ private Button btnCompressFile;
+ private OpenFileDialog openFileDialog;
+ private StatusStrip statusStrip;
+ private ToolStripStatusLabel toolStripStatusLabel;
+ private ToolStripProgressBar toolStripProgressBar1;
+ private Button btnInflateFile;
}
diff --git a/HufmannCompressorWinFormsApp/MainForm.cs b/HufmannCompressorWinFormsApp/MainForm.cs
index 3f5329b..69ada1d 100644
--- a/HufmannCompressorWinFormsApp/MainForm.cs
+++ b/HufmannCompressorWinFormsApp/MainForm.cs
@@ -1,43 +1,41 @@
-namespace HufmannCompressorWinFormsApp
+namespace HufmannCompressor.WinFormsApp;
+using HuffmanCompressor.Lib;
+
+public partial class MainForm : Form
{
- using HuffmanCompressorLib;
+ public MainForm()
+ {
+ InitializeComponent();
+ }
- public partial class MainForm : Form
+ private void btnCompressFile_Click(object sender, EventArgs e)
{
- public MainForm()
+ openFileDialog.Filter = "All files (*.*)|*.*";
+ var openFileDialogResult = openFileDialog.ShowDialog(this);
+ if (openFileDialogResult != DialogResult.OK)
{
- InitializeComponent();
+ return;
}
- private void btnCompressFile_Click(object sender, EventArgs e)
- {
- openFileDialog.Filter = "All files (*.*)|*.*";
- var openFileDialogResult = openFileDialog.ShowDialog(this);
- if (openFileDialogResult != DialogResult.OK)
- {
- return;
- }
-
- var compressor = new HuffmanCompressor();
- toolStripStatusLabel.Text = "Compressing...";
- compressor.Compress(openFileDialog.FileName, openFileDialog.FileName + ".huf");
- toolStripStatusLabel.Text = "Ready";
- }
+ var compressor = new HuffmanCompressor();
+ toolStripStatusLabel.Text = "Compressing...";
+ compressor.Compress(openFileDialog.FileName, openFileDialog.FileName + ".huf");
+ toolStripStatusLabel.Text = "Ready";
+ }
- private void btnInflateFile_Click(object sender, EventArgs e)
+ private void btnInflateFile_Click(object sender, EventArgs e)
+ {
+ openFileDialog.Filter = "Compressed files (*.huf)|*.huf";
+ openFileDialog.AddExtension = true;
+ var openFileDialogResult = openFileDialog.ShowDialog(this);
+ if (openFileDialogResult != DialogResult.OK)
{
- openFileDialog.Filter = "Compressed files (*.huf)|*.huf";
- openFileDialog.AddExtension = true;
- var openFileDialogResult = openFileDialog.ShowDialog(this);
- if (openFileDialogResult != DialogResult.OK)
- {
- return;
- }
-
- var compressor = new HuffmanCompressor();
- toolStripStatusLabel.Text = "Inflating...";
- compressor.Inflate(openFileDialog.FileName, openFileDialog.FileName + ".inflated");
- toolStripStatusLabel.Text = "Ready";
+ return;
}
+
+ var compressor = new HuffmanCompressor();
+ toolStripStatusLabel.Text = "Inflating...";
+ compressor.Inflate(openFileDialog.FileName, openFileDialog.FileName + ".inflated");
+ toolStripStatusLabel.Text = "Ready";
}
}
\ No newline at end of file
diff --git a/HufmannCompressorWinFormsApp/Program.cs b/HufmannCompressorWinFormsApp/Program.cs
index fdfa4e8..f43e41b 100644
--- a/HufmannCompressorWinFormsApp/Program.cs
+++ b/HufmannCompressorWinFormsApp/Program.cs
@@ -1,4 +1,4 @@
-namespace HufmannCompressorWinFormsApp
+namespace HufmannCompressor.WinFormsApp
{
internal static class Program
{
From a7697f1c384441f5c05fd823568e8551ff569bc3 Mon Sep 17 00:00:00 2001
From: LuisMSuarez <140195810+LuisMSuarez@users.noreply.github.com>
Date: Wed, 27 Aug 2025 12:50:44 -0700
Subject: [PATCH 2/3] Folder restructure
---
.../AssemblyInfo.cs | 0
.../HuffmanCompressor.Cmd.csproj | 2 +-
.../Program.cs | 0
.../BitReader.cs | 0
.../BitWriter.cs | 0
.../FrequencyCounter.cs | 0
.../HuffmanCompressor.Lib.csproj | 0
.../HuffmanCompressor.cs | 0
.../IFileCompressor.cs | 0
.../Node.cs | 0
.../Properties/AssemblyInfo.cs | 0
.../Properties/launchSettings.json | 0
.../CodeCoverage/coverageReport.zip | Bin
.../CodeCoverage/report.png | Bin
.../EndToEndTests.cs | 0
.../FrequencyCounterTests.cs | 0
.../HuffmanCompressor.Tests.csproj | 4 ++--
.../HuffmanCompressorTests.cs | 0
.../ProgramTests.cs | 0
.../TestData/E2E-EmptyFile.txt | 0
.../TestData/E2E-SingleCharacter.txt | 0
.../TestData/E2E-SmallFile.txt | 0
.../TestData/E2E-WordFile.docx | Bin
.../TestData/EmptyFile.txt | 0
.../TestData/SingleCharacter.txt | 0
.../TestData/SmallFile.txt | 0
.../TestData/WordFile.docx | Bin
.../Utilities.cs | 0
HuffmanCompressor.sln | 8 ++++----
.../HuffmanCompressor.WinFormsApp.csproj | 2 +-
.../MainForm.Designer.cs | 0
.../MainForm.cs | 0
.../MainForm.resx | 0
.../Program.cs | 0
34 files changed, 8 insertions(+), 8 deletions(-)
rename {HuffmanCompressorCmd => HuffmanCompressor.Cmd}/AssemblyInfo.cs (100%)
rename {HuffmanCompressorCmd => HuffmanCompressor.Cmd}/HuffmanCompressor.Cmd.csproj (75%)
rename {HuffmanCompressorCmd => HuffmanCompressor.Cmd}/Program.cs (100%)
rename {HuffmanCompressor => HuffmanCompressor.Lib}/BitReader.cs (100%)
rename {HuffmanCompressor => HuffmanCompressor.Lib}/BitWriter.cs (100%)
rename {HuffmanCompressor => HuffmanCompressor.Lib}/FrequencyCounter.cs (100%)
rename {HuffmanCompressor => HuffmanCompressor.Lib}/HuffmanCompressor.Lib.csproj (100%)
rename {HuffmanCompressor => HuffmanCompressor.Lib}/HuffmanCompressor.cs (100%)
rename {HuffmanCompressor => HuffmanCompressor.Lib}/IFileCompressor.cs (100%)
rename {HuffmanCompressor => HuffmanCompressor.Lib}/Node.cs (100%)
rename {HuffmanCompressor => HuffmanCompressor.Lib}/Properties/AssemblyInfo.cs (100%)
rename {HuffmanCompressor => HuffmanCompressor.Lib}/Properties/launchSettings.json (100%)
rename {HuffmanCompressorTests => HuffmanCompressor.Tests}/CodeCoverage/coverageReport.zip (100%)
rename {HuffmanCompressorTests => HuffmanCompressor.Tests}/CodeCoverage/report.png (100%)
rename {HuffmanCompressorTests => HuffmanCompressor.Tests}/EndToEndTests.cs (100%)
rename {HuffmanCompressorTests => HuffmanCompressor.Tests}/FrequencyCounterTests.cs (100%)
rename {HuffmanCompressorTests => HuffmanCompressor.Tests}/HuffmanCompressor.Tests.csproj (91%)
rename {HuffmanCompressorTests => HuffmanCompressor.Tests}/HuffmanCompressorTests.cs (100%)
rename {HuffmanCompressorTests => HuffmanCompressor.Tests}/ProgramTests.cs (100%)
rename {HuffmanCompressorTests => HuffmanCompressor.Tests}/TestData/E2E-EmptyFile.txt (100%)
rename {HuffmanCompressorTests => HuffmanCompressor.Tests}/TestData/E2E-SingleCharacter.txt (100%)
rename {HuffmanCompressorTests => HuffmanCompressor.Tests}/TestData/E2E-SmallFile.txt (100%)
rename {HuffmanCompressorTests => HuffmanCompressor.Tests}/TestData/E2E-WordFile.docx (100%)
rename {HuffmanCompressorTests => HuffmanCompressor.Tests}/TestData/EmptyFile.txt (100%)
rename {HuffmanCompressorTests => HuffmanCompressor.Tests}/TestData/SingleCharacter.txt (100%)
rename {HuffmanCompressorTests => HuffmanCompressor.Tests}/TestData/SmallFile.txt (100%)
rename HuffmanCompressorTests/TestData/wordFile.docx => HuffmanCompressor.Tests/TestData/WordFile.docx (100%)
rename {HuffmanCompressorTests => HuffmanCompressor.Tests}/Utilities.cs (100%)
rename {HufmannCompressorWinFormsApp => HufmannCompressor.WinFormsApp}/HuffmanCompressor.WinFormsApp.csproj (78%)
rename {HufmannCompressorWinFormsApp => HufmannCompressor.WinFormsApp}/MainForm.Designer.cs (100%)
rename {HufmannCompressorWinFormsApp => HufmannCompressor.WinFormsApp}/MainForm.cs (100%)
rename {HufmannCompressorWinFormsApp => HufmannCompressor.WinFormsApp}/MainForm.resx (100%)
rename {HufmannCompressorWinFormsApp => HufmannCompressor.WinFormsApp}/Program.cs (100%)
diff --git a/HuffmanCompressorCmd/AssemblyInfo.cs b/HuffmanCompressor.Cmd/AssemblyInfo.cs
similarity index 100%
rename from HuffmanCompressorCmd/AssemblyInfo.cs
rename to HuffmanCompressor.Cmd/AssemblyInfo.cs
diff --git a/HuffmanCompressorCmd/HuffmanCompressor.Cmd.csproj b/HuffmanCompressor.Cmd/HuffmanCompressor.Cmd.csproj
similarity index 75%
rename from HuffmanCompressorCmd/HuffmanCompressor.Cmd.csproj
rename to HuffmanCompressor.Cmd/HuffmanCompressor.Cmd.csproj
index 372a954..f63b6b6 100644
--- a/HuffmanCompressorCmd/HuffmanCompressor.Cmd.csproj
+++ b/HuffmanCompressor.Cmd/HuffmanCompressor.Cmd.csproj
@@ -8,7 +8,7 @@
-
+
diff --git a/HuffmanCompressorCmd/Program.cs b/HuffmanCompressor.Cmd/Program.cs
similarity index 100%
rename from HuffmanCompressorCmd/Program.cs
rename to HuffmanCompressor.Cmd/Program.cs
diff --git a/HuffmanCompressor/BitReader.cs b/HuffmanCompressor.Lib/BitReader.cs
similarity index 100%
rename from HuffmanCompressor/BitReader.cs
rename to HuffmanCompressor.Lib/BitReader.cs
diff --git a/HuffmanCompressor/BitWriter.cs b/HuffmanCompressor.Lib/BitWriter.cs
similarity index 100%
rename from HuffmanCompressor/BitWriter.cs
rename to HuffmanCompressor.Lib/BitWriter.cs
diff --git a/HuffmanCompressor/FrequencyCounter.cs b/HuffmanCompressor.Lib/FrequencyCounter.cs
similarity index 100%
rename from HuffmanCompressor/FrequencyCounter.cs
rename to HuffmanCompressor.Lib/FrequencyCounter.cs
diff --git a/HuffmanCompressor/HuffmanCompressor.Lib.csproj b/HuffmanCompressor.Lib/HuffmanCompressor.Lib.csproj
similarity index 100%
rename from HuffmanCompressor/HuffmanCompressor.Lib.csproj
rename to HuffmanCompressor.Lib/HuffmanCompressor.Lib.csproj
diff --git a/HuffmanCompressor/HuffmanCompressor.cs b/HuffmanCompressor.Lib/HuffmanCompressor.cs
similarity index 100%
rename from HuffmanCompressor/HuffmanCompressor.cs
rename to HuffmanCompressor.Lib/HuffmanCompressor.cs
diff --git a/HuffmanCompressor/IFileCompressor.cs b/HuffmanCompressor.Lib/IFileCompressor.cs
similarity index 100%
rename from HuffmanCompressor/IFileCompressor.cs
rename to HuffmanCompressor.Lib/IFileCompressor.cs
diff --git a/HuffmanCompressor/Node.cs b/HuffmanCompressor.Lib/Node.cs
similarity index 100%
rename from HuffmanCompressor/Node.cs
rename to HuffmanCompressor.Lib/Node.cs
diff --git a/HuffmanCompressor/Properties/AssemblyInfo.cs b/HuffmanCompressor.Lib/Properties/AssemblyInfo.cs
similarity index 100%
rename from HuffmanCompressor/Properties/AssemblyInfo.cs
rename to HuffmanCompressor.Lib/Properties/AssemblyInfo.cs
diff --git a/HuffmanCompressor/Properties/launchSettings.json b/HuffmanCompressor.Lib/Properties/launchSettings.json
similarity index 100%
rename from HuffmanCompressor/Properties/launchSettings.json
rename to HuffmanCompressor.Lib/Properties/launchSettings.json
diff --git a/HuffmanCompressorTests/CodeCoverage/coverageReport.zip b/HuffmanCompressor.Tests/CodeCoverage/coverageReport.zip
similarity index 100%
rename from HuffmanCompressorTests/CodeCoverage/coverageReport.zip
rename to HuffmanCompressor.Tests/CodeCoverage/coverageReport.zip
diff --git a/HuffmanCompressorTests/CodeCoverage/report.png b/HuffmanCompressor.Tests/CodeCoverage/report.png
similarity index 100%
rename from HuffmanCompressorTests/CodeCoverage/report.png
rename to HuffmanCompressor.Tests/CodeCoverage/report.png
diff --git a/HuffmanCompressorTests/EndToEndTests.cs b/HuffmanCompressor.Tests/EndToEndTests.cs
similarity index 100%
rename from HuffmanCompressorTests/EndToEndTests.cs
rename to HuffmanCompressor.Tests/EndToEndTests.cs
diff --git a/HuffmanCompressorTests/FrequencyCounterTests.cs b/HuffmanCompressor.Tests/FrequencyCounterTests.cs
similarity index 100%
rename from HuffmanCompressorTests/FrequencyCounterTests.cs
rename to HuffmanCompressor.Tests/FrequencyCounterTests.cs
diff --git a/HuffmanCompressorTests/HuffmanCompressor.Tests.csproj b/HuffmanCompressor.Tests/HuffmanCompressor.Tests.csproj
similarity index 91%
rename from HuffmanCompressorTests/HuffmanCompressor.Tests.csproj
rename to HuffmanCompressor.Tests/HuffmanCompressor.Tests.csproj
index 2e50fdf..4bbc4cd 100644
--- a/HuffmanCompressorTests/HuffmanCompressor.Tests.csproj
+++ b/HuffmanCompressor.Tests/HuffmanCompressor.Tests.csproj
@@ -19,8 +19,8 @@
-
-
+
+
diff --git a/HuffmanCompressorTests/HuffmanCompressorTests.cs b/HuffmanCompressor.Tests/HuffmanCompressorTests.cs
similarity index 100%
rename from HuffmanCompressorTests/HuffmanCompressorTests.cs
rename to HuffmanCompressor.Tests/HuffmanCompressorTests.cs
diff --git a/HuffmanCompressorTests/ProgramTests.cs b/HuffmanCompressor.Tests/ProgramTests.cs
similarity index 100%
rename from HuffmanCompressorTests/ProgramTests.cs
rename to HuffmanCompressor.Tests/ProgramTests.cs
diff --git a/HuffmanCompressorTests/TestData/E2E-EmptyFile.txt b/HuffmanCompressor.Tests/TestData/E2E-EmptyFile.txt
similarity index 100%
rename from HuffmanCompressorTests/TestData/E2E-EmptyFile.txt
rename to HuffmanCompressor.Tests/TestData/E2E-EmptyFile.txt
diff --git a/HuffmanCompressorTests/TestData/E2E-SingleCharacter.txt b/HuffmanCompressor.Tests/TestData/E2E-SingleCharacter.txt
similarity index 100%
rename from HuffmanCompressorTests/TestData/E2E-SingleCharacter.txt
rename to HuffmanCompressor.Tests/TestData/E2E-SingleCharacter.txt
diff --git a/HuffmanCompressorTests/TestData/E2E-SmallFile.txt b/HuffmanCompressor.Tests/TestData/E2E-SmallFile.txt
similarity index 100%
rename from HuffmanCompressorTests/TestData/E2E-SmallFile.txt
rename to HuffmanCompressor.Tests/TestData/E2E-SmallFile.txt
diff --git a/HuffmanCompressorTests/TestData/E2E-WordFile.docx b/HuffmanCompressor.Tests/TestData/E2E-WordFile.docx
similarity index 100%
rename from HuffmanCompressorTests/TestData/E2E-WordFile.docx
rename to HuffmanCompressor.Tests/TestData/E2E-WordFile.docx
diff --git a/HuffmanCompressorTests/TestData/EmptyFile.txt b/HuffmanCompressor.Tests/TestData/EmptyFile.txt
similarity index 100%
rename from HuffmanCompressorTests/TestData/EmptyFile.txt
rename to HuffmanCompressor.Tests/TestData/EmptyFile.txt
diff --git a/HuffmanCompressorTests/TestData/SingleCharacter.txt b/HuffmanCompressor.Tests/TestData/SingleCharacter.txt
similarity index 100%
rename from HuffmanCompressorTests/TestData/SingleCharacter.txt
rename to HuffmanCompressor.Tests/TestData/SingleCharacter.txt
diff --git a/HuffmanCompressorTests/TestData/SmallFile.txt b/HuffmanCompressor.Tests/TestData/SmallFile.txt
similarity index 100%
rename from HuffmanCompressorTests/TestData/SmallFile.txt
rename to HuffmanCompressor.Tests/TestData/SmallFile.txt
diff --git a/HuffmanCompressorTests/TestData/wordFile.docx b/HuffmanCompressor.Tests/TestData/WordFile.docx
similarity index 100%
rename from HuffmanCompressorTests/TestData/wordFile.docx
rename to HuffmanCompressor.Tests/TestData/WordFile.docx
diff --git a/HuffmanCompressorTests/Utilities.cs b/HuffmanCompressor.Tests/Utilities.cs
similarity index 100%
rename from HuffmanCompressorTests/Utilities.cs
rename to HuffmanCompressor.Tests/Utilities.cs
diff --git a/HuffmanCompressor.sln b/HuffmanCompressor.sln
index 6085d43..d543e5f 100644
--- a/HuffmanCompressor.sln
+++ b/HuffmanCompressor.sln
@@ -3,13 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.7.34202.233
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HuffmanCompressor.Lib", "HuffmanCompressor\HuffmanCompressor.Lib.csproj", "{93160A18-48C3-4AB8-A9C9-2EA2D2C46B01}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HuffmanCompressor.Lib", "HuffmanCompressor.Lib\HuffmanCompressor.Lib.csproj", "{93160A18-48C3-4AB8-A9C9-2EA2D2C46B01}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HuffmanCompressor.Tests", "HuffmanCompressorTests\HuffmanCompressor.Tests.csproj", "{304D0AF6-D701-40E9-8A2F-E2508A12ED5F}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HuffmanCompressor.Tests", "HuffmanCompressor.Tests\HuffmanCompressor.Tests.csproj", "{304D0AF6-D701-40E9-8A2F-E2508A12ED5F}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HuffmanCompressor.WinFormsApp", "HufmannCompressorWinFormsApp\HuffmanCompressor.WinFormsApp.csproj", "{78D7EB54-F5CB-45E8-B293-2B95EA522589}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HuffmanCompressor.WinFormsApp", "HufmannCompressor.WinFormsApp\HuffmanCompressor.WinFormsApp.csproj", "{78D7EB54-F5CB-45E8-B293-2B95EA522589}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HuffmanCompressor.Cmd", "HuffmanCompressorCmd\HuffmanCompressor.Cmd.csproj", "{567B674B-79D9-4331-A6D6-A13735DA3327}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HuffmanCompressor.Cmd", "HuffmanCompressor.Cmd\HuffmanCompressor.Cmd.csproj", "{567B674B-79D9-4331-A6D6-A13735DA3327}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
diff --git a/HufmannCompressorWinFormsApp/HuffmanCompressor.WinFormsApp.csproj b/HufmannCompressor.WinFormsApp/HuffmanCompressor.WinFormsApp.csproj
similarity index 78%
rename from HufmannCompressorWinFormsApp/HuffmanCompressor.WinFormsApp.csproj
rename to HufmannCompressor.WinFormsApp/HuffmanCompressor.WinFormsApp.csproj
index 7b72cf3..403991f 100644
--- a/HufmannCompressorWinFormsApp/HuffmanCompressor.WinFormsApp.csproj
+++ b/HufmannCompressor.WinFormsApp/HuffmanCompressor.WinFormsApp.csproj
@@ -9,7 +9,7 @@
-
+
\ No newline at end of file
diff --git a/HufmannCompressorWinFormsApp/MainForm.Designer.cs b/HufmannCompressor.WinFormsApp/MainForm.Designer.cs
similarity index 100%
rename from HufmannCompressorWinFormsApp/MainForm.Designer.cs
rename to HufmannCompressor.WinFormsApp/MainForm.Designer.cs
diff --git a/HufmannCompressorWinFormsApp/MainForm.cs b/HufmannCompressor.WinFormsApp/MainForm.cs
similarity index 100%
rename from HufmannCompressorWinFormsApp/MainForm.cs
rename to HufmannCompressor.WinFormsApp/MainForm.cs
diff --git a/HufmannCompressorWinFormsApp/MainForm.resx b/HufmannCompressor.WinFormsApp/MainForm.resx
similarity index 100%
rename from HufmannCompressorWinFormsApp/MainForm.resx
rename to HufmannCompressor.WinFormsApp/MainForm.resx
diff --git a/HufmannCompressorWinFormsApp/Program.cs b/HufmannCompressor.WinFormsApp/Program.cs
similarity index 100%
rename from HufmannCompressorWinFormsApp/Program.cs
rename to HufmannCompressor.WinFormsApp/Program.cs
From cb65b398c79b6b22d00d31ae7800102d65cc88cb Mon Sep 17 00:00:00 2001
From: LuisMSuarez <140195810+LuisMSuarez@users.noreply.github.com>
Date: Wed, 27 Aug 2025 13:07:31 -0700
Subject: [PATCH 3/3] Added DI nuget package and set up DI in Program class
---
.../HuffmanCompressor.Cmd.csproj | 4 +++
HuffmanCompressor.Cmd/Program.cs | 31 ++++++++++++-------
HuffmanCompressor.Tests/ProgramTests.cs | 12 +++----
3 files changed, 28 insertions(+), 19 deletions(-)
diff --git a/HuffmanCompressor.Cmd/HuffmanCompressor.Cmd.csproj b/HuffmanCompressor.Cmd/HuffmanCompressor.Cmd.csproj
index f63b6b6..83fdd4d 100644
--- a/HuffmanCompressor.Cmd/HuffmanCompressor.Cmd.csproj
+++ b/HuffmanCompressor.Cmd/HuffmanCompressor.Cmd.csproj
@@ -7,6 +7,10 @@
enable
+
+
+
+
diff --git a/HuffmanCompressor.Cmd/Program.cs b/HuffmanCompressor.Cmd/Program.cs
index a95fc6f..964ed06 100644
--- a/HuffmanCompressor.Cmd/Program.cs
+++ b/HuffmanCompressor.Cmd/Program.cs
@@ -1,4 +1,7 @@
namespace HuffmanCompressor.Cmd;
+
+using System;
+using Microsoft.Extensions.DependencyInjection;
using HuffmanCompressor.Lib;
///
@@ -11,18 +14,20 @@ public class Program
///
/// Constructor of the Program class.
///
- public Program()
+ public Program(IFileCompressor compressor)
{
- _compressor = new HuffmanCompressor();
+ _compressor = compressor;
}
///
- /// Internal method intended for the unit tests to be able to inject a mock interface for testing purposes.
+ /// The main entry point (Main method) for the application.
///
- /// Instance of the compressor interface.
- internal void SetCompressorReference(IFileCompressor compressor)
+ /// Program arguments.
+ public static void Main(string[] args)
{
- _compressor = compressor;
+ var serviceProvider = ConfigureServices();
+ var program = new Program(serviceProvider.GetRequiredService());
+ program.Run(args);
}
///
@@ -60,12 +65,16 @@ public void Run(string[] args)
}
///
- /// Main entry point for the HuffmanCompressorCmd console application.
+ /// Configures dependency injection container.
///
- /// Program arguments.
- public static void Main(string[] args)
+ /// Service provider with registered services.
+ private static IServiceProvider ConfigureServices()
{
- var program = new Program();
- program.Run(args);
+ var services = new ServiceCollection();
+
+ // Register IFileCompressor with HuffmanCompressor
+ services.AddTransient();
+
+ return services.BuildServiceProvider();
}
}
\ No newline at end of file
diff --git a/HuffmanCompressor.Tests/ProgramTests.cs b/HuffmanCompressor.Tests/ProgramTests.cs
index c6aea10..ac531eb 100644
--- a/HuffmanCompressor.Tests/ProgramTests.cs
+++ b/HuffmanCompressor.Tests/ProgramTests.cs
@@ -11,8 +11,7 @@ public void CompressMethodInvokedWithCompressParameterTest()
// Arrange
var mockCompressor = new Mock(MockBehavior.Strict);
mockCompressor.Setup(c => c.Compress(It.IsAny(), It.IsAny()));
- var program = new Program();
- program.SetCompressorReference(mockCompressor.Object);
+ var program = new Program(mockCompressor.Object);
// Act
program.Run(["compress", "input.txt", "output.bin" ]);
@@ -30,8 +29,7 @@ public void InflateMethodInvokedWithCompressParameterTest()
// Arrange
var mockCompressor = new Mock(MockBehavior.Strict);
mockCompressor.Setup(c => c.Inflate(It.IsAny(), It.IsAny()));
- var program = new Program();
- program.SetCompressorReference(mockCompressor.Object);
+ var program = new Program(mockCompressor.Object);
// Act
program.Run(["inflate", "input.bin", "output.txt"]);
@@ -48,8 +46,7 @@ public void ArgumentExceptionThrownWithInvalidCommandTest()
{
// Arrange
var mockCompressor = new Mock(MockBehavior.Strict);
- var program = new Program();
- program.SetCompressorReference(mockCompressor.Object);
+ var program = new Program(mockCompressor.Object);
// Act & Assert
Assert.Throws(
@@ -63,8 +60,7 @@ public void ArgumentExceptionThrownWithInvalidNumberOfParametersTest(string comm
{
// Arrange
var mockCompressor = new Mock(MockBehavior.Strict);
- var program = new Program();
- program.SetCompressorReference(mockCompressor.Object);
+ var program = new Program(mockCompressor.Object);
// Act & Assert
Assert.Throws(