Abnerson+Malivert+Project+1

toc

= = = = = = = = = = = = =SSE-659 PROJECT 1=

1.0 OBJECTIVE
The objective of this project is to cover Refactoring topics from chapter 3 to chapter 7. Refactoring is used to make code easier to follow and understand and also improves the design of the software and the speed at which your software execute. Software that are refactored are easier to find and fix bugs. In this report I will go through refactoring topics and make changes to improve the design of different open source software.

2.0 Looking for smelly code
In this section, I will go through different coding formats found in the Be.HexEditor software that should be refactored according to ch.3 of the Marten Fowler Refactoring book. For each common coding format mistakes, I will find an open source code snippet that contains that error and will provide the way to fix it in section 3.

2.1 Duplicated code
A duplicated code format is when the same code structure is in more than one place. Duplicated codes can be either having the same expression in two methods of the same class, or having the same expression in two methods of the same class. The easiest way to fix duplicated code is to unifying them. Bellow is snippet code from Be.HexEditor open source software: code format="csharp" public FormOptions {           InitializeComponent;

this.recentFilesMax = Settings.Default.RecentFilesMax; this.recentFilesMaxTextBox.DataBindings.Add("Text", this, "RecentFilesMax"); this.useSystemLanguage = Settings.Default.UseSystemLanguage; this.useSystemLanguageCheckBox.DataBindings.Add("Checked", this, "UseSystemLanguage");

if (string.IsNullOrEmpty(Settings.Default.SelectedLanguage)) Settings.Default.SelectedLanguage = CultureInfo.CurrentCulture.TwoLetterISOLanguageName;

DataTable dt = new DataTable; **dt.Columns.Add("Name", typeof(string));** **dt.Columns.Add("Value", typeof(string));** **dt.Rows.Add(strings.English, "en");** **dt.Rows.Add(strings.German, "de");** **dt.Rows.Add(strings.Japanese, "ja");** **dt.Rows.Add(strings.Russian, "ru");** **dt.DefaultView.Sort = "Name";**

this.languageComboBox.DataSource = dt.DefaultView; this.languageComboBox.DisplayMember = "Name"; this.languageComboBox.ValueMember = "Value"; this.languageComboBox.SelectedValue = Settings.Default.SelectedLanguage; if (this.languageComboBox.SelectedIndex == -1) this.languageComboBox.SelectedIndex = 0; }

code If you look at the code in between the **, adding the new table and columns are duplicated code because you have code that are similar but not the same. The way to fix the above code is to use the extract method found in section 3.

2.2 Long Method
Shorter methods are easier to read and understanding. When refactoring existing code you should look to shorten long methods, and try to make them as short as possible. One way to shorten a method is to use the extract method to shorten the method or use the Replace Method with Method Object method. Bellow is a snippet of code from the Be.HexEditor from the FormHexEditor.cs class: code format="csharp" ///        /// Opens a file. ///        /// the file name of the file to open public void OpenFile(string fileName) {           if (!File.Exists(fileName)) {               Program.ShowMessage(strings.FileDoesNotExist); return; }

if (hexBox.ByteProvider != null) {               if (CloseFile == DialogResult.Cancel) return; }

try {               DynamicFileByteProvider dynamicFileByteProvider; try {                   // try to open in write mode dynamicFileByteProvider = new DynamicFileByteProvider(fileName); dynamicFileByteProvider.Changed += new EventHandler(byteProvider_Changed); dynamicFileByteProvider.LengthChanged += new EventHandler(byteProvider_LengthChanged); }               catch (IOException) // write mode failed {                   try {                       // try to open in read-only mode dynamicFileByteProvider = new DynamicFileByteProvider(fileName, true); if (Program.ShowQuestion(strings.OpenReadonly) == DialogResult.No) {                           dynamicFileByteProvider.Dispose; return; }                   }                    catch (IOException) // read-only also failed {                       // file cannot be opened Program.ShowError(strings.OpenFailed); return; }               }

hexBox.ByteProvider = dynamicFileByteProvider; _fileName = fileName;

DisplayText;

UpdateFileSizeStatus;

recentFileHandler.AddFile(fileName); }           catch (Exception ex1) {               Program.ShowError(ex1); return; }           finally {               ManageAbility; }       } code The OpenFile method above is part of the FormHexEditor class and is a very long method. I could use the extract method to refactor the method, but that would require a lot of work, since it doesn't really have duplicated code, instead I am going to use the Replace Method with Method Object method, the solution is found in section 3.1.

2.3 Large Class

Large class is when a class has too many instances and also has a lot of code which leads to confusion or hard to read and understand code. One way to fix a large class is to use the Extract Class method. Large classes increases the opportunity to have duplicated code. code format="csharp" using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.IO; using System.Windows.Forms; using Be.Windows.Forms;

namespace Be.HexEditor {   public partial class FormHexEditor : Form {       FormFind _formFind = new FormFind; FormFindCancel _formFindCancel; FormGoTo _formGoto = new FormGoTo; byte[] _findBuffer = new byte[0]; string _fileName;

public FormHexEditor {           InitializeComponent;

Init; }

///        /// Initializes the hex editor´s main form ///        void Init {           DisplayText;

ManageAbility; }

///        /// Updates the File size status label ///        void UpdateFileSizeStatus {           if (this.hexBox.ByteProvider == null) this.fileSizeToolStripStatusLabel.Text = string.Empty; else this.fileSizeToolStripStatusLabel.Text = Util.GetDisplayBytes(this.hexBox.ByteProvider.Length); }

///        /// Displays the file name in the Form´s text property ///        /// the file name to display void DisplayText {           if (_fileName != null && _fileName.Length > 0) {               string textFormat = "{0}{1} - {2}"; string sReadOnly = ((DynamicFileByteProvider)hexBox.ByteProvider).ReadOnly ? strings.Readonly : ""; string text = Path.GetFileName(_fileName); this.Text = string.Format(textFormat, text, sReadOnly, Program.SOFTWARENAME); }           else {               this.Text = Program.SOFTWARENAME; }       }

///        /// Manages enabling or disabling of menu items and toolstrip buttons. ///        void ManageAbility {           if (hexBox.ByteProvider == null) {               saveToolStripMenuItem.Enabled = saveToolStripButton.Enabled = false;

findToolStripMenuItem.Enabled = false; findNextToolStripMenuItem.Enabled = false; goToToolStripMenuItem.Enabled = false;

selectAllToolStripMenuItem.Enabled = false; }           else {               saveToolStripMenuItem.Enabled = saveToolStripButton.Enabled = hexBox.ByteProvider.HasChanges;

findToolStripMenuItem.Enabled = true; findNextToolStripMenuItem.Enabled = true; goToToolStripMenuItem.Enabled = true;

selectAllToolStripMenuItem.Enabled = true; }

ManageAbilityForCopyAndPaste; }

///        /// Manages enabling or disabling of menustrip items and toolstrip buttons for copy and paste ///        void ManageAbilityForCopyAndPaste {           copyHexStringToolStripMenuItem.Enabled = copyToolStripSplitButton.Enabled = copyToolStripMenuItem.Enabled = hexBox.CanCopy;

cutToolStripButton.Enabled = cutToolStripMenuItem.Enabled = hexBox.CanCut; pasteToolStripSplitButton.Enabled = pasteToolStripMenuItem.Enabled = hexBox.CanPaste; pasteHexToolStripMenuItem.Enabled = pasteHexToolStripMenuItem1.Enabled = hexBox.CanPasteHex; }

///        /// Shows the open file dialog. ///        void OpenFile {           if (openFileDialog.ShowDialog == DialogResult.OK) {               OpenFile(openFileDialog.FileName); }       }

///        /// Opens a file. ///        /// the file name of the file to open public void OpenFile(string fileName) {           if (!File.Exists(fileName)) {               Program.ShowMessage(strings.FileDoesNotExist); return; }

if (hexBox.ByteProvider != null) {               if (CloseFile == DialogResult.Cancel) return; }

try {               DynamicFileByteProvider dynamicFileByteProvider; try {                   // try to open in write mode dynamicFileByteProvider = new DynamicFileByteProvider(fileName); dynamicFileByteProvider.Changed += new EventHandler(byteProvider_Changed); dynamicFileByteProvider.LengthChanged += new EventHandler(byteProvider_LengthChanged); }               catch (IOException) // write mode failed {                   try {                       // try to open in read-only mode dynamicFileByteProvider = new DynamicFileByteProvider(fileName, true); if (Program.ShowQuestion(strings.OpenReadonly) == DialogResult.No) {                           dynamicFileByteProvider.Dispose; return; }                   }                    catch (IOException) // read-only also failed {                       // file cannot be opened Program.ShowError(strings.OpenFailed); return; }               }

hexBox.ByteProvider = dynamicFileByteProvider; _fileName = fileName;

DisplayText;

UpdateFileSizeStatus;

recentFileHandler.AddFile(fileName); }           catch (Exception ex1) {               Program.ShowError(ex1); return; }           finally {               ManageAbility; }       }

///        /// Saves the current file. ///        void SaveFile {           if (hexBox.ByteProvider == null) return;

try {               DynamicFileByteProvider dynamicFileByteProvider = hexBox.ByteProvider as DynamicFileByteProvider; dynamicFileByteProvider.ApplyChanges; }           catch (Exception ex1) {               Program.ShowError(ex1); }           finally {               ManageAbility; }       }

///        /// Closes the current file ///        /// OK, if the current file was closed. DialogResult CloseFile {           if (hexBox.ByteProvider == null) return DialogResult.OK;

try

{               if (hexBox.ByteProvider != null && hexBox.ByteProvider.HasChanges) {                   DialogResult res = MessageBox.Show(strings.SaveChangesQuestion,                        Program.SOFTWARENAME,                        MessageBoxButtons.YesNoCancel,                        MessageBoxIcon.Warning);

if (res == DialogResult.Yes) {                       SaveFile; CleanUp; }                   else if (res == DialogResult.No) {                       CleanUp; }                   else if (res == DialogResult.Cancel) {                       return res; }

return res; }               else {                   CleanUp; return DialogResult.OK; }           }            finally {               ManageAbility; }       }

void CleanUp {           if (hexBox.ByteProvider != null) {               IDisposable byteProvider = hexBox.ByteProvider as IDisposable; if (byteProvider != null) byteProvider.Dispose; hexBox.ByteProvider = null; }           _fileName = null; DisplayText; }

///        /// Opens the Find dialog ///        void Find {           if (_formFind.ShowDialog == DialogResult.OK) {               _findBuffer = _formFind.GetFindBytes; FindNext; }       }

///        /// Find next match ///        void FindNext {           if (_findBuffer.Length == 0) {               Find; return; }

// show cancel dialog _formFindCancel = new FormFindCancel; _formFindCancel.SetHexBox(hexBox); _formFindCancel.Closed += new EventHandler(FormFindCancel_Closed); _formFindCancel.Show;

// block activation of main form Activated += new EventHandler(FocusToFormFindCancel);

// start find process long res = hexBox.Find(_findBuffer, hexBox.SelectionStart + hexBox.SelectionLength);

_formFindCancel.Dispose;

// unblock activation of main form Activated -= new EventHandler(FocusToFormFindCancel);

if (res == -1) // -1 = no match {               MessageBox.Show(strings.FindOperationEndOfFile, Program.SOFTWARENAME,                    MessageBoxButtons.OK, MessageBoxIcon.Information); }           else if (res == -2) // -2 = find was aborted {               return; }           else // something was found {               if (!hexBox.Focused) hexBox.Focus; }

ManageAbility; }

///        /// Aborts the current find process ///        void FormFindCancel_Closed(object sender, EventArgs e)        { hexBox.AbortFind; }

///        /// Put focus back to the cancel form. ///        void FocusToFormFindCancel(object sender, EventArgs e)        { _formFindCancel.Focus; }

///        /// Displays the goto byte dialog. ///        void Goto {           _formGoto.SetMaxByteIndex(hexBox.ByteProvider.Length); _formGoto.SetDefaultValue(hexBox.SelectionStart); if (_formGoto.ShowDialog == DialogResult.OK) {               hexBox.SelectionStart = _formGoto.GetByteIndex; hexBox.SelectionLength = 1; hexBox.Focus; }       }

///        /// Enables drag&drop ///        void hexBox_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)        { e.Effect = DragDropEffects.All; }

///        /// Processes a file drop ///        void hexBox_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)        { string[] formats = e.Data.GetFormats; object oFileNames = e.Data.GetData(DataFormats.FileDrop); string[] fileNames = (string[])oFileNames; if (fileNames.Length == 1) {               OpenFile(fileNames[0]); }       }

void hexBox_Copied(object sender, EventArgs e)       { ManageAbilityForCopyAndPaste; }

void hexBox_CopiedHex(object sender, EventArgs e)       { ManageAbilityForCopyAndPaste; }

void hexBox_SelectionLengthChanged(object sender, System.EventArgs e)       { ManageAbilityForCopyAndPaste; }

void hexBox_SelectionStartChanged(object sender, System.EventArgs e)       { ManageAbilityForCopyAndPaste; }

void Position_Changed(object sender, EventArgs e)       { this.toolStripStatusLabel.Text = string.Format("Ln {0}   Col {1}",                hexBox.CurrentLine, hexBox.CurrentPositionInLine); }

void byteProvider_Changed(object sender, EventArgs e)       { ManageAbility; }

void byteProvider_LengthChanged(object sender, EventArgs e)       { UpdateFileSizeStatus; }

void open_Click(object sender, EventArgs e)       { OpenFile; }

void save_Click(object sender, EventArgs e)       { SaveFile; }

void cut_Click(object sender, EventArgs e)       { this.hexBox.Cut; }

private void copy_Click(object sender, EventArgs e)       { this.hexBox.Copy; }

void paste_Click(object sender, EventArgs e)       { this.hexBox.Paste; }

private void copyHex_Click(object sender, EventArgs e)       { this.hexBox.CopyHex; }

private void pasteHex_Click(object sender, EventArgs e)       { this.hexBox.PasteHex; }

void find_Click(object sender, EventArgs e)       { this.Find; }

void goTo_Click(object sender, EventArgs e)       { this.Goto; }

void selectAllToolStripMenuItem_Click(object sender, EventArgs e)       { this.hexBox.SelectAll; }

void exit_Click(object sender, EventArgs e)       { this.Close; }

void about_Click(object sender, EventArgs e)       { new FormAbout.ShowDialog; }

void recentFiles_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)       { RecentFileHandler.FileMenuItem fmi = (RecentFileHandler.FileMenuItem)e.ClickedItem; this.OpenFile(fmi.Filename); }

void options_Click(object sender, EventArgs e)       { new FormOptions.ShowDialog; }

} } code The FormHexEditor.cs class is part of the Be.HexEditor software. I am going to shrink the size of the class using the Extract Class method. The solution can be found in section 3.3.

3.0 Refactoring the Be.HexEditor Software
This section about fixing the findings from section 2. The methods that are used to refactor the BE.HexEditor code can be found in the "Refactoring" Martin Frowler book chapter 6 and 7. In the next sections, I will go through each of the findings and provide a solution for them.

3.1 Extract Method
The code from section 2.1 contains duplicated methods that can be extracted from the FormOption method and turn into its own method. The Extract method is used when you have a code that is too long or hard to understand. It takes fragments of code and turns them into their own method. Bellow is the new code using the extract method to fix the code snippet from section 2.1: code format="csharp" public FormOptions {           InitializeComponent;

this.recentFilesMax = Settings.Default.RecentFilesMax; this.recentFilesMaxTextBox.DataBindings.Add("Text", this, "RecentFilesMax"); this.useSystemLanguage = Settings.Default.UseSystemLanguage; this.useSystemLanguageCheckBox.DataBindings.Add("Checked", this, "UseSystemLanguage");

if (string.IsNullOrEmpty(Settings.Default.SelectedLanguage)) Settings.Default.SelectedLanguage = CultureInfo.CurrentCulture.TwoLetterISOLanguageName;

DataTable dt = new DataTable; addDataTable(dt);

this.languageComboBox.DataSource = dt.DefaultView; this.languageComboBox.DisplayMember = "Name"; this.languageComboBox.ValueMember = "Value"; this.languageComboBox.SelectedValue = Settings.Default.SelectedLanguage; if (this.languageComboBox.SelectedIndex == -1) this.languageComboBox.SelectedIndex = 0; }

public void addDataTable(DataTable _dt) {           _dt.Columns.Add("Name", typeof(string)); _dt.Columns.Add("Value", typeof(string)); _dt.Rows.Add(strings.English, "en"); _dt.Rows.Add(strings.German, "de"); _dt.Rows.Add(strings.Japanese, "ja"); _dt.Rows.Add(strings.Russian, "ru"); _dt.DefaultView.Sort = "Name"; }

code

The code above is the result of using the extract method to make the FormOptions method cleaner. I took the DataTable codes out of the FormOptions method, then created a new method called addDataTable method. The addDataTable method takes in a DataTable parameter. The OptionForm creates an instance of DataTable (like the original code), but instead of having 7 more lines of code that are similar, it calls the addDataTable method. The FormOption method is now cleaner and easier to understand. The addDataTable method makes it easier to pin point bugs in the software.

3.2 Replace Method with Method Object
The OpenFile code from section 2.2 is a long method. long methods are hard to understand and follow and also leads to having a large class. I decided to use the Replace Method with Method Object option to refactor the OpenFile method from section 2.2. The Replace Method with Method Object method is when you create a new class named after the method that's used to replace the method. The code bellow is the OpenFile.cs that I created to shrink down the OpenFile method in the HexForm.cs class.

code format="csharp" using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.IO; using System.Windows.Forms; using Be.Windows.Forms;

namespace Be.HexEditor {   class OpenFile {       private string fileName; private string _fileName; HexBox hexBox; FormHexEditor _formhexeditor = new FormHexEditor;

public OpenFile(string _FileName, HexBox _HexBox) {           this.hexBox = _HexBox; this.fileName = _FileName; }

public void Compute {           if (!File.Exists(fileName)) {               Program.ShowMessage(strings.FileDoesNotExist); return; }

if (hexBox.ByteProvider != null) {

if (_formhexeditor.CloseFile == DialogResult.Cancel) return; }

try {               DynamicFileByteProvider dynamicFileByteProvider; try {

// try to open in write mode dynamicFileByteProvider = new DynamicFileByteProvider(fileName); dynamicFileByteProvider.Changed += new EventHandler(_formhexeditor.byteProvider_Changed); dynamicFileByteProvider.LengthChanged += new EventHandler(_formhexeditor.byteProvider_LengthChanged); }               catch (IOException) // write mode failed {                   try {                       // try to open in read-only mode dynamicFileByteProvider = new DynamicFileByteProvider(fileName, true); if (Program.ShowQuestion(strings.OpenReadonly) == DialogResult.No) {                           dynamicFileByteProvider.Dispose; return; }                   }                    catch (IOException) // read-only also failed {                       // file cannot be opened Program.ShowError(strings.OpenFailed); return; }               }

hexBox.ByteProvider = dynamicFileByteProvider; _fileName = fileName;

_formhexeditor.DisplayText;

_formhexeditor.UpdateFileSizeStatus;

_formhexeditor.recentFileHandler.AddFile(fileName); }           catch (Exception ex1) {               Program.ShowError(ex1); return; }           finally {               _formhexeditor.ManageAbility; }       }        public string FileName {           get { return fileName; } set { fileName = value; } }   }

}

code

Looking at the code above, all the compute power from the OpenFile method are transferred to the OpenFile.cs class. Constructors are built for the variables from the OpenMethod method. The result from using the Replace Method with Method Object method to refactor the HexForm.cs class resulted in a smaller method that went from over 90 lines to 1 line.

Bellow is the new OpenFile Method. The OpenFile method in the HexForm.cs class makes new instances of the OpenForm.cs class.

code format="csharp" public void OpenFile(string fileName) {           OpenFile _OpenFile = new OpenFile(fileName, hexBox); } code

3.3 Extract Class Method
The Extract Class method is going to be used to shrink down the large FormHexEditor.cs class. Extract Class method is when you take out a method or a group of methods with similar responsibilities and turn them into their own class. The Extract Class method class shrinks down a large class by taking away roles and responsibilities away from the large class.

Looking at the FormHexEditor.cs class the openfile method was refactored by using the Extract Method method. The CloseFile method can also be refactored using the Extract Method mehtod. Below is the CloseFile.cs class after the CloseFile method from the FormHexEditor is refactored.

code format="csharp" using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.IO; using System.Windows.Forms; using Be.Windows.Forms;

namespace Be.HexEditor {   class CloseFile {

HexBox hexBox; FormHexEditor _formhexeditor = new FormHexEditor;

public CloseFile(HexBox _HexBox) {           this.hexBox = _HexBox;

}       public DialogResult Compute {           if (hexBox.ByteProvider == null) return DialogResult.OK;

try {               if (hexBox.ByteProvider != null && hexBox.ByteProvider.HasChanges) {                   DialogResult res = MessageBox.Show(strings.SaveChangesQuestion,                        Program.SOFTWARENAME,                        MessageBoxButtons.YesNoCancel,                        MessageBoxIcon.Warning);

if (res == DialogResult.Yes) {                       _formhexeditor.SaveFile; _formhexeditor.CleanUp; }                   else if (res == DialogResult.No) {                       _formhexeditor.CleanUp; }                   else if (res == DialogResult.Cancel) {                       return res; }

return res; }               else {                   _formhexeditor.CleanUp; return DialogResult.OK; }           }            finally {               Manage _manage = new Manage; _manage.ManageAbility; }       }

} }

code The CloseFile method in the FormHexEditor.cs class is now cleaner and smaller, which also makes the FormHexEditor.cs class smaller and cleaner. The code bellow is the refactored CloseFile method. code format="csharp" public DialogResult CloseFile {           CloseFile _CloseFile = new CloseFile(hexBox); return _CloseFile.Compute; }

code Looking at the FormHexEditor.cs in section 2.3 the ManageAbility and the ManageAbilityForCopyAndPaste methods have similar roles and responsibilities and can be grouped together in one class. Using the Extract Class method, I took the ManageAbility and the ManageAbilityForCopyAndPaste and form the Manage.cs class. Bellow is the Manage.cs class.

code format="csharp" using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.IO; using System.Windows.Forms; using Be.Windows.Forms;

namespace Be.HexEditor {   class Manage {       //HexBox hexBox; FormHexEditor _formhexeditor = new FormHexEditor; public Manage {           //this.hexBox = _HexBox; }

public void ManageAbility {           HexBox hexBox = new HexBox; if (hexBox.ByteProvider == null) {               _formhexeditor.saveToolStripMenuItem.Enabled = _formhexeditor.saveToolStripButton.Enabled = false;

_formhexeditor.findToolStripMenuItem.Enabled = false; _formhexeditor.findNextToolStripMenuItem.Enabled = false; _formhexeditor.goToToolStripMenuItem.Enabled = false;

_formhexeditor.selectAllToolStripMenuItem.Enabled = false; }           else {               _formhexeditor.saveToolStripMenuItem.Enabled = _formhexeditor.saveToolStripButton.Enabled = hexBox.ByteProvider.HasChanges;

_formhexeditor.findToolStripMenuItem.Enabled = true; _formhexeditor.findNextToolStripMenuItem.Enabled = true; _formhexeditor.goToToolStripMenuItem.Enabled = true;

_formhexeditor.selectAllToolStripMenuItem.Enabled = true; }

ManageAbilityForCopyAndPaste; }

///        /// Manages enabling or disabling of menustrip items and toolstrip buttons for copy and paste ///        public void ManageAbilityForCopyAndPaste {           HexBox hexBox = new HexBox; _formhexeditor.copyHexStringToolStripMenuItem.Enabled = _formhexeditor.copyToolStripSplitButton.Enabled = _formhexeditor.copyToolStripMenuItem.Enabled = hexBox.CanCopy;

_formhexeditor.cutToolStripButton.Enabled = _formhexeditor.cutToolStripMenuItem.Enabled = hexBox.CanCut; _formhexeditor.pasteToolStripSplitButton.Enabled = _formhexeditor.pasteToolStripMenuItem.Enabled = hexBox.CanPaste; _formhexeditor.pasteHexToolStripMenuItem.Enabled = _formhexeditor.pasteHexToolStripMenuItem1.Enabled = hexBox.CanPasteHex; }

} }

code The FormHexEditor.cs class is now smaller and leaner and easier to understand after refactoring it using the Extract Class and The Extract Method methods. The FormHexEditor.cs class is not perfect or the way that I would like to have it, but some of the changes I could not make without changing everything else or risk introducing new bugs into the software.

4.0 Building Test with NUNIT
Unit testing is important to writing bug free code. According to the Refactoring book by Marten Fowler, the test class should be the first class written when developing software because it will save time and headache. Programmer uses unit testing to see how the program will handle different situations and if it's reacting the way that it supposed to.

NUnit is an open source unit testing framework for .NET programming that uses the JUnit library. NUnit can be downloaded from http://www.nunit.org/index.php?p=download. NUnit can be used to test .NET project and .dll files using a unit test class. NUnit can be used in console or gui mode. Bellow is a screenshot of the NUnit-GUI.



4.1 NUnit Test Class

I wrote an OpenFileTest.cs class to test the OpenFile.cs class from section 3.2.The OpenFileTest.cs NUnit class needs to test every situation that can lead throw an error in the OpenFile.cs class. Looking at the OpenFile.cs class, we are going to test :


 * 1) When a file does not exist => The expected result should be that it fails and throws an error message since the IOException is being handled.
 * 2) When a file exists => The expected result should be that it passes the test.
 * 3) When a file is write and read protected => The expected result should be that it fails and throws an error message since the IOException is being handled.
 * 4) When a file is write protected => The expected result is that it should fail and not be able to open the file.
 * 5) When a file is read protected => The expected result is that it should pass and the file should open in write mode.

Bellow is the OpenFileTest.cs class:


 * 1) The [TestFixture] is the way to indicate that the class contains test code.
 * 2) The [SetUp] is to set the initiallization codes.
 * 3) The [Test] is the way to indicated a test.

code format="csharp" using System; using System.Collections.Generic; using System.Text; using System.IO; using Be.Windows.Forms; using System.Windows.Forms; //using Be.HexEditor;

namespace Be.HexEditor {   using NUnit.Framework;

[TestFixture] public class OpenFileTest {       private string _fileName; private OpenFile _OpenFile; private HexBox _HexBox; private FormHexEditor _FormHexEditor;

[SetUp] protected void SetUp {           _HexBox = new HexBox; _FormHexEditor = new FormHexEditor;

}

[Test] public void FileDoesExist {           _fileName = @"C:\Users\Administrator\Desktop\FileExist.txt"; _OpenFile = new OpenFile(_fileName, _HexBox); _OpenFile.Compute; }

[Test] public void FileDoesNotExist {

_fileName = @"C:\Users\Administrator\Desktop\test.txt"; _OpenFile = new OpenFile(_fileName, _HexBox); _OpenFile.Compute;

}

[Test] public void ReadWriteModeDenied {           _fileName = @"C:\Users\Administrator\Desktop\FileReadWriteDenied.txt"; _OpenFile = new OpenFile(_fileName, _HexBox); _OpenFile.Compute;

}

[Test] public void FileReadOnly {           _fileName = @"C:\Users\Administrator\Desktop\FileReadOnly.txt"; _OpenFile = new OpenFile(_fileName, _HexBox); _OpenFile.Compute;

}

[Test] public void FileWriteOnly {           _fileName = @"C:\Users\Administrator\Documents\Desktop\FileWriteOnly.txt"; _OpenFile = new OpenFile(_fileName, _HexBox); _OpenFile.Compute;

}

} }

code

4.1.2 Open File test
I tested the FileOpen.cs class by giving it a path to a file that existed and also had full access. The result should just be nothing happening since no error messages are thrown. Bellow is a screenshot of the result :



4.1.3 File does not exist test
I tested the OpenFile.cs class with a file path that did not include the file indicated. The result is that an errror message should of popped up. Bellow is a record of that message:



4.1.4 File read only access
I tested the OpenFile.cs class by opening a file that can only be open in read mode. The result of the test should be that the file is open in write mode. The result below is wrong, it was working before, I tried countless time to fix it but it wouldnt show the right message. It worked before, but stop working, I think it has something to do with me using parallel windows to run windows on my mac. Bellow is a screenshot of the result, the result should of been read only access message.



I tested the OpenFile.cs class by opening a file that can only be open in write mode only. The result of the test should be that we have no access to the file since you can't open a file in write mode only. The result bellow displays the satisfactory result.



4.1.6 File read and write access denied
I wrote a test for the OpenFile.cs class that tested if it would give an error if I try to open file that locked both read and write access. The expected result is that it should give an error since it has no access to the file. the image bellow reflects the expected result.