Thursday, January 31, 2008

VBScript debug and execute

Keywords: VBscript, debugger, execute


同事要我帮助他修改他的一个VBScript脚本, 当我收到邮件后, 我在想, 1.我该怎样运行这个脚本; 2. 我该使用什么编辑器?; 3.有没有比较好的script调试器?


首先google, 微软最新的脚本执行器为Microsoft script 5.7 版本. 需要download并install. 执行脚本的方法是: cscript yourscript.vbs [options], 详见cscript /?


用什么编辑器编辑VB script呢? 最好能有intellisense功能, Visual studio 6有一个这样的编辑器. 但可以使用Office软件的VBA editor.

Zip Rar Outlook Excel Word password remove tool

Keywords: password remove


trial version: http://www.apasscracker.com/download/


It has can only recovery a few pdf pages if trial version was used.


and this company has also other password crack tools, for zip, rar, GoogleTalk, MSN, Outlook, Excel, Word, PST file.

PDF restriction remove tool

Keywords: decrypt pdf, allow print permission, change permission restrication


Some ebooks are in pdf format, but they probably have some permission restrication, such as disable print or save.


There are some tools that can remove the restrications.


1. PDF password remover 3.0


http://www.verypdf.com/


its registration key maker: http://crackdb.org/get_112804_PDF.Password.Remover.v3.0_crack.html


2. Atomic PDF Password Recovery


trial version: http://www.apasscracker.com/download/


It has can only recovery a few pdf pages if trial version was used.


and this company has also other password crack tools, for zip, rar, GoogleTalk, MSN, Outlook, Excel, Word, PST file.

Wednesday, January 30, 2008

short introduction of c# syntax

Keywords: C#, Syntax


i sometimes forget some c# basic. There are some links which can help me keep in mind.


Sharp New Language: C# Offers the Power of C++ and Simplicity of Visual Basic


http://msdn.microsoft.com/msdnmag/issues/0900/csharp/default.aspx


C++ -> C#: What You Need to Know to Move from C++ to C#


http://msdn.microsoft.com/msdnmag/issues/01/07/ctocsharp/


Nice Things About C#


http://www.cs.princeton.edu/~cdecoro/csharp.html

Tuesday, January 29, 2008

Download Web Content other than using WebClient class

Keywords: WebClient, UTF-8, WebRequest


从一个URI上下载网页Content或Xml, 可以直接使用WebClient类(在System.Net命名空间), 非常简单. 它有很多Download方法, 比如DownloadString()和DownloadFile(). 这些都是同步方法, 当然它也有异步Download方法, 不过经常用的是它的同步方法.


但在用WebClient.DownloadString()一个以UTF-8编码格式存盘的一个Xml文件时, 得到的Xml字符串有乱码, 不管怎样设置WebClient的Encode属性都没有用处, 可能是WebClient的一个bug吧.


可以WebRequest方法来实现同步DownloadString的功能. 代码如下:




public void DownloadAndLoadXml(string uri, XmlDocument doc)
{
System.Net.WebRequest request = System.Net.WebRequest.Create(uri);
using (System.Net.WebResponse response=request.GetResponse())
using (System.IO.Stream stream=response.GetResponseStream())
{
if (stream.Length > 0)
{
stream.Position = 0;
doc.Load(stream);
}
}
}



/// <summary>
/// download the web page from the given uri
/// </summary>
/// <param name="uri"></param>
/// <returns></returns>
public string DownloadStringFromWeb(string uri)
{
System.Net.WebRequest request = System.Net.WebRequest.Create(uri);
using (System.Net.WebResponse response = request.GetResponse())
using (System.IO.Stream stream = response.GetResponseStream())
{
System.IO.StreamReader reader = new StreamReader(stream);
//save all info from stream into a string variable
string result=reader.ReadToEnd();
reader.Close();
return result;
}
}

XmlBeautifier tool development

Keywords: Event, Class Inherit, Drag and drop supported


Preface


一直想写一个具有实际功能的C#例程, 来加深我对C# Event和Delegate的理解. 这个例程最好不要太庞大, 因为庞大的程序需要考虑的东西太多, 容易跑题. 碰巧在项目中, 经常需要查看Word2007的docx文件包中Xml文件(注: docx格式为zip格式, 里面包含很多xml文件, 但这些xml文件的element没有缩进). 我喜欢用Notepad++这个编辑器, 但用Notepad++不支持没有缩进的xml的collapse element功能, 浏览起来并不直观. 所以打算写一个小工具, 能够缩进xml的element. 这个工具我命名为XmlBeautifier.


Dev Environment:


Visual Studio 2005, .Net Framework 2.0, .Net Framework 3.0


System Design


XmlBeautifier设计初衷是能处理docx中的xml文件, 为了使它更具通用性, 它应该还能处理单个的xml文件, 最好还能批量处理一个目录下的所有xml文件. 我设计一个抽象基类SourcePackage, 它有3个子类, 分别是DirectoryPackage(负责批量处理某个目录下所有文件的美化), DocxPackage(负责处理docx文件), 以及SingleFilePackage(负责处理单一xml文件) .


SourcePackage类是整个程序的核心. CollectFileStream()是一个抽象方法, 负责获取这个包中的所有文件的流, 三个子类都要实现这个方法; 因为需要将包中文件以流的形式加载到内存, 所以SourcePackage类需要实现IDisposable接口, 来释放文件流资源; BeautifyFiles()负责执行xml文件的美化工作, 当把所有的文件以流的形式加载到一个m_ListFileStream后, BeautifyFiles()方法就很简单, 循环各个文件流, 分别美化它们.



Extra Features Design


一个好的程序应该是用户友好型的, 对于我们这样的小工具, 也要做到这样. 为此, 我为这个工具增加2个必要的feature. F1. 用户能够处理的进度; F2.工具支持文件(或目录)的拖拉处理.


F1. 为了是工具能实时显示处理的进度, 需要为SourcePackage类增加两个事件Handler, 一个是OneXmlProcessedHandler(当一个文件被处理完后, 这个Handler会被Invoke); 另一个是ProcessOverHandler(当整个文件包被处理完毕后, 这个Handler会被Invoke). 这2个Handler的类型为delegate, 分别为OneXmlProcessedEventHandler, ProcessOverEventHandler. 为了能将Package的文件总数和当前处理的文件Index传给UI类, 我定义了ProcessCountEventArgs这个类, 这样UI类的EventHandler就能获取这些信息. 有关事件的详细论述, 请看我的另一篇文章 .




F2. 拖拉的支持


C#的Form和Panel都有个bool型属性AllowDrop, 只要AllowDrop=true, 你就可以在资源管理器中将文件或目录拖到Form(或Panel)上, 只不过鼠标Cursor不对头, 在Panel的DragEnter事件中设置DragEventArgs参数的Effect就可以.


当文件 ( 或目录 )Drop 到 Panel 后 , 需要美化这些文档 , 在 Panel 的 DragDrop 事件中调用相应的代码就可 . 调用之前需判断 Drop 下的东西是否是文件或目录 .


private void panelDrop_DragDrop(object sender, DragEventArgs e)


{


if (e.Data.GetDataPresent(DataFormats.FileDrop))


{


String[] filenames = (String[])e.Data.GetData(DataFormats.FileDrop);


textBoxSourcePath.Text = filenames[0];


ProcessBeautify() ;


}


}


主要类的 Class Diagram 见下图 .



代码下载 (xmlBeautifier_Src.zip ), 可执行文件下载 (XmlBeautifier_Bin.zip )

Monday, January 28, 2008

disable the screensaver broadcasted on the intranet

Keywords: Screen Saver


公司电脑屏保非常烦人, 3分钟不用, 就启动屏保, 退出屏保要输密码. 禁止屏保的办法是修改注册表.


Registry Entry: HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\Control Panel\Desktop

Sunday, January 27, 2008

understand event of c#

Keywords: Event, delegate, Publish and subscribe pattern


我打算设计一个程序, 它能一次性美化一个目录之下所有的xml文件, 在UI上, 要求能显示处理的进度(即每处理完一个xml文件, UI的ProgressBar就变化一下). 美化xml的由SourcePackage类的BeautifyFiles方法完成, 而UI是另一个类FormMain. 显然这要处理SourcePackage类和FormMain类之间的通讯问题. 怎样解决这个问题呢? 这其实这是一个如何解耦的问题.


如果你学过C语言, 你会很自然想到使用回调函数, 即在FormMain类中新增一个方法, 比如UpdateProgressBar(), 然后将UpdateProgressBar()这个函数传给SourcePackage.BeautifyFiles()方法. 这确实是一个解决方法. 即将一个被调用者传给调用者. 这种方法直接有效, 但耦合度很高.


另一个方案是, 采用Publish-Subscribe模式, 使用这个模式, 首先要定义一个通知, 即发布什么, 以及订阅什么. 就本实例来讲, 这个通知就是一个xml文件已经被处理完了, 在UI类中, 订阅这个通知, 然后再编写这个通知的一个Handler函数(即进行更新进度条).


C#就是采用Publish-Subscribe来实现Event, 因为C#Delegate支持多播, 所以非常完美地实现了Publish-subscribe; 如果你使用C++, 也可采用了Observer模式来实现Event. 我们用C#的Event来实现设计要求. 设计的详细思路是:


在Publish方(Publish方多数为一个服务的服务端), 需要完成的工作是:


(1) 如果需要的话,使用delegate来定义通知类型, (一般的EventHandler已经在Framework中定义了, 特殊的Handler需要自定义)


public delegate void OneXmlProcessedEventHandler(object sender, ProcessCountEventArgs e);


(2) 在SourcePackage类中, 使用event关键字来发布通知.


public event OneXmlProcessedEventHandler OneXmlProcessed;


(3) 在SourcePackage.BeautifyFiles()触发这个通知的Handler.


foreach (Stream fileStream in m_ListFileStream)


{


m_FileBeautifier.FileStream = fileStream;


m_FileBeautifier.Beautify();


if (OneXmlProcessed != null)


{


eventArgs.ProcessedIndex = eventArgs.ProcessedIndex+1 ;


OneXmlProcessed(this, eventArgs);


}


}


在Subscribe方(Subscribe方多为服务的消费端), 需要完成的工作是:


(1) 订阅这个通知


SourcePackage sourcePackage = new SourcePackage(packageFullName);


sourcePackage.OneXmlProcessed += new OneXmlProcessedEventHandler(OneXmlProcessedHandler);



(2) 编写通知Handler


void OneXmlProcessedHandler(object sender, ProcessCountEventArgs e)


{


const string progressIndicator="{0} of {1} is proceeded!" ;


toolStripStatusLabel1.Text = string.Format(progressIndicator, e.ProcessedIndex, e.FileCount);


toolStripProgressBar1.Value = e.ProcessedIndex;


Application.DoEvents();


}







Friday, January 25, 2008

how to use XmlDocument.Save and XmlWriter

Keywords: XmlDocument class, XmlWriter, FileStream, StringBuilder


原本想使用XmlWriter来格式化一个文件流, 结果是: Xml是被格式化了, 但格式化后的字符串是append到原来的流中, 而不是重写到文件流中. 为什么会出现这个现象呢? 我们先分析一下原来的代码:




public void BeautifyXml(FileStream fileStream)
{
XmlDocument xmlDoc = new XmlDocument();

//1. 重置m_fileStream的position为0, 否则xmlDoc.Load可能会出现异常
fileStream.Position = 0;

//2. 加载m_FileStream的内容到xmlDoc
xmlDoc.Load(fileStream);

//3. 创建一个XmlWriterSettings对象, 设置它的Format
XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
xmlWriterSettings.Indent = true;
xmlWriterSettings.IndentChars = " ";

//4.创建一个输出到fileStream的XmlWriter
XmlWriter writer = XmlWriter.Create(fileStream, xmlWriterSettings);

//5.保存XmlDocument的内容, 即输出到fileStream
xmlDoc.Save(writer);
}

在step2之后,XmlDoc对象已经完成Xml的加载, 然后在step4创建了一个输出到fileStream的XmlWriter, step5用xmlDoc.Save(writer)输出Xml到流中. 可以想象保存动作执行顺序应该是xmlDoc.Save()--->writer--->fileStream, 在保存时fileStream还保存着原来未被格式化的内容, 所以writer将xml的内容追加到fileStream. 知道问题的原因, 解决方案就简单了. 在step5之前先将fileStream的内容清空,可以用下面语句


fileStream.SetLength(0);

Thursday, January 24, 2008

Hide program window by using HideWindowHotkey software


Keywords: Hide program software window, Hide Window Hotkey


Hide Window Hotkey is a utility which allows you to hide the windows, and programs which are running on your screen.It will instantly hide or close all (or some) programs through mouse hotkey or keyboard hotkey.It also could resize your programs automatically,such as maximize, minimize,normal,minimize to tray.


http://www.elongsoft.com


Minimize software window to system tray


Keywords: Tools, Minimize software window to TrayIcon


Trayconizer, This is a cool little software. It allows you to minimize almost applications to system tray. Using Trayconizer is simple. To start TrayConizer on Notepad, you would execute: c:\Path\to\Trayconizer.exe c:\windows\notepad.exe


http://www.whitsoftdev.com/trayconizer/




Wednesday, January 23, 2008

Getting Started with NUnit

Getting Started with NUnit

Richard Davis, SharpLogic Software

In this article, we will take a look at unit testing, test-driven development, and the NUnit framework. If you are already familiar with these topics and are instead looking for information about how it all ties in with the Software Design Competition, feel free to skip ahead to the NUnit and the Software Design Competition section.

Prerequisite

Read and complete the steps described in the Getting Started With The Software Design Competition article. This will give you a cursory introduction to the process of using the NUnit GUI application to run test code.

Requirements and Setup

One of the great advantages of competing in the Imagine Cup Software Design Competition is that you’re able to use the best tools available, and they’re absolutely free!

  1. Download and install a version of Visual Studio 2005 Express from http://msdn.microsoft.com/vstudio/express/. You can use any language to develop your class library, but the baseline source code and tests are provided in C# so you’ll need to have that installed if you want to use them. Install with the default settings.

    Note: You may use any version of Visual Studio 2005 that you have available.

  1. Download the “NUnit 2.2.8 for .NET 2.0 MSI” installer from http://www.nunit.org/index.php?p=download and install it with the default settings.
  2. Download the practice Level 100 Tutorial challenge from http://imaginecup.sharplogic.com/Challenge.aspx?challenge=4265d098-52ac-4eb6-8549-e8ab652d99b8 and unzip it to a convenient location, such as “C:L100MathLib”. At this point you should have a directory structure that looks like the following:



Unzip the challenge package (C:L100MathLibL100Math.zip) to the “C:L100MathLib” directory so that its contents are placed into the “C:L100MathLibL100Math” directory. The resulting directory should look like the following:


Test-Driven Development and Unit Testing

Testing software is an integral phase of the development lifecycle. As software projects grow in size, so too does the complexity. Complexity can refer to the size of the source code base, architecture and design of components, number of code paths, and even algorithmic considerations. The decisions to be made about testing have to do with the “when” and the “how”, not the “why”.

Software testing provides a valuable means to help verify that software was build correctly, but it can also serve as a form of requirements specification up front. Consider the development of a method that computes the division of two integral numbers:

public int Divide(int dividend, int divisor)

{ }

To devise tests for this method we need to think like a tester. This process includes asking questions like the following:

  • What are the types of input and what is the set of values they can possess?
  • What is the expected return type? Are there any restrictions to be considered upon return to the caller?
  • If the input includes reference types, is null (C#) or nothing (VB.NET) ever passed in?

It is important to identify and test for cases where state and input lead to faulty operation. In the case of the Divide method, we can determine that the operation is invalid when the divisor input is zero. Next, we can write a test to exercise the Divide method and check for the desired response. In the case of the Divide method, we expect a System.DivideByZeroException to be thrown when the divisor input is zero.

The test method that we just devised is a type of unit test. Unit tests typically look for a very specific result from an operation. This means that there is often a many to one relationship of tests to one piece of code. Consider the Divide method once again. We already have one test designed, but we also want tests that make sure various valid inputs return the correct results.

As you can see from the Divide example, the development of unit tests can be done before the application code is implemented. This process is known as test-driven development, and it provides many benefits:

  • Requirements are self-documented.
  • Tests are automatic and repeatable.
  • Tests are designed to work with known bad and good input values.


The development of unit tests provides an automatic and repeatable method for verifying the correct functioning of code. Each time code is added or modified in a project, the suite of unit tests can be re-run to make sure that the changes did not break functionality that worked previously. The act of re-running a suite of unit tests is known as regression testing.

Keep in mind that unit testing does not guarantee that software will be free of bugs. Generally speaking, it is not realistic to get full code path coverage that exercises the entire set and combinations of input to all methods in a piece of software. In addition, the quality of testing relies solely on the developer of the tests. There may be cases where a unit test fails to identify problems in code. Nevertheless, test-driven development and unit testing are powerful allies to have throughout the software development lifecycle.

Developing Tests for NUnit

In this section, we will walk through the development of some simple unit tests that target the NUnit testing framework. Make sure that you have downloaded and installed the L100Math example as described in the Requirements and Setup section before continuing.

  1. Load the L100Math solution file with Visual Studio 2005:
  1. Double-click on the L100Math.sln file that you previously downloaded and extracted to your computer (C:L100MathLibL100MathL100Math.sln).
  1. Double-click on the MathHelperTests.cs source file.



  1. Examine the MathHelperTests class found within the MathHelperTests.cs source file. Notice that the test class has an attribute named TestFixture attached to it. This attribute is defined as part of the NUnit framework and is used by NUnit to determine which classes contain tests.
  2. Examine the test methods found within the MathHelperTests.cs source file:
  1. There are two test methods designed to test the functionality of the MathHelper.Add method, TestAdd and TestAdd2.
  1. Each test method is marked with the Test attribute so that NUnit can locate designated tests.
  2. Each test method is responsible for conducting tests in way that allows the NUnit framework to determine when a test is a success or failure. This is done by using the NUnit Assert class. In the TestAdd test method, we add 3 and 5 together and store the result. Next, the Assert.AreEqual method is given the expected result, the actual result, and a message to be presented to the user in case the provided values are not equal.



  1. Add a new test method to the MathHelperTests class which tests for the raising of a DivideByZeroException when the divisor parameter is zero:
  1. Copy and paste the following code:

    [Test]

    [ExpectedException(typeof(DivideByZeroException))]

    public void TestDivide2()

    {

int quotient = MathHelper.Divide(4, 0);

    }

  1. Here we used another NUnit framework attribute named ExpectedException to inform NUnit that the test will be considered a success if the specified DivideByZeroException exception type is thrown.
  2. Note that we could alternatively wrap the call to the MathHelper.Divide method within a try…catch block. The test will succeed in this case because we prevent the DivideByZeroException from being propagated up the call stack to the NUnit framework.

    [Test]

    public void TestDivide2()

    {

    try

    {

    int quotient = MathHelper.Divide(4, 0);

    Assert.Fail("MathHelper.Divide(4, 0) " +

    "failed to throw a DivideByZeroException.");

    }

    catch (DivideByZeroException)

    {

    }

    }

It is important to note the requirements for the most essential NUnit framework attributes, TestFixture and Test. TestFixture requires the following from the class that it is applied to:

  • Public scope.
  • A public, default constructor without parameters.

If a method that is marked with the TestFixture attribute does not have a default constructor with the correct signature, i.e. you marked it as private instead of public; all tests will fail to run. The reason will be listed under the Tests Not Run tab as shown below.

Note: You should just leave out the constructor unless you need to perform initialization.


The Test attribute requires the following from the method that it is applied to:

  • Public scope.
  • Void return type.
  • No parameters.

If a method that is marked with the Test attribute does not return void, the test will not be run by NUnit and the reason why will be listed under the Tests Not Run tab as shown below.



Assertions are another very important topic to become familiar with as you gain more experience using the NUnit platform. The Assert.AreEqual method, which we just saw in action, is categorized as an equality assertion by NUnit. Another type of equality assertion is the Assert.AreNotEqual method, which does exactly what its name implies. Other categories of assertion include identity, comparison, type, and condition. The following tables describe a number of the different assertion categories and their methods:

    Equality Asserts

    Method Description
    Assert.AreEqual Tests whether the expected and actual arguments are equal, asserting when they are not equal.
    Assert.AreNotEqual Opposite of AreEqual method.
    Examples
    // This example shows a successful AreEqual test.

    int expected = 5;

    int actual = 5;

    Assert.AreEqual(expected, actual, "Expected and actual values are not

    equal.");


Identity Asserts

Method Description
Assert.AreSame Tests whether the expected and actual arguments are the same object reference, asserting when they are not the same.
Assert.AreNotSame Opposite of AreSame method.
Assert.Contains Tests whether an object is contained in an array or list.
Examples
// This example shows a successful AreSame test.

object objA = new object();

object objB = objA;

Assert.AreSame(objA, objB, "Object references are not the same.");

// This example shows a successful Contains test.

string[] myArray = { "a", "b", "c" };

Assert.Contains("b", myArray, "Array does not contain expected

value.");


Comparison Asserts

Method Description
Assert.Greater Tests whether one object is greater than another.
Assert.Less Tests whether one object is less than another.
Examples
// This example shows a successful Less test (arg1 < arg2).

int arg1 = 5;

int arg2 = 6;

Assert.Less(arg1, arg2);


Type Asserts

Method Description
IsInstanceOfType Tests whether an object is of a specified type or derived from a specified type, asserting when it is not.
IsNotInstanceOfType Opposite of IsInstanceOfType method.
IsAssignableFrom Tests whether it is valid to assign an instance of the specified type to a given object, asserting if it is not.
IsNotAssignableFrom Opposite of IsAssignableFrom method.
Examples
// This example shows a successful IsInstanceOfType test.

Exception myException = new Exception();

Assert.IsInstanceOfType(typeof(Exception), myException);

// This example shows a successful IsAssignableFrom test.

object myObject = new object();

Assert.IsAssignableFrom(typeof(Exception), myObject);

Exception myException = new Exception();

// Assertion guarantees that myObject can be assigned myException (or // any other object that is typeof(Exception)).

myObject = myException;


Condition Asserts

Method Description
Assert.IsTrue Tests whether a boolean condition is true, asserting when it is not.
Assert.IsFalse Tests whether a boolean condition is false, asserting when it is.
Assert.IsNull Tests whether an object is null, asserting when it is not.
Assert.IsNotNull Opposite of IsNull method.
Assert.IsNaN Tests whether a double is not a number (NaN), asserting when it is not.
Assert.IsEmpty One overload tests whether a string is empty (string.Empty or “”), asserting when it is not.

Another overload tests whether a collection or array is empty, asserting when it is not.

Assert.IsNotEmpty Opposite of IsEmpty method.
Examples
// This example shows an unsuccessful IsNotEmpty test.

List<int> myList = new List<int>();

Assert.IsNotEmpty(myList, "List is empty.");


Utility Asserts

Method Description
Assert.Fail Throws an AssertionException with specified failure message.
Assert.Ignore Causes the current test to be ignored.
Examples
// This example shows a custom assertion that fails when the

// myDouble variable does not fit within the specified value range.

double myDouble = 0.94;

if (myDouble < 0.95 || myDouble > 1.05)

{

Assert.Fail("Value is not within the specified range.");

}


String Asserts

Method Description
StringAssert.Contains Tests whether a string contains an expected substring, asserting when it does not.
StringAssert.StartsWith Tests whether a string starts with an expected substring, asserting when it does not.
StringAssert.EndsWith Tests whether a string ends with an expected substring, asserting when it does not.
StringAssert.AreEqualIgnoringCase Tests whether an expected string is equal to an actual string ignoring case, asserting when they are not.
Examples
// This example shows a successful AreEqualIgnoringCase test.

string actual = "test";

StringAssert.AreEqualIgnoringCase("tEsT", actual);

Running Tests Using NUnit

Assuming that you satisfied the prerequisite listed at the beginning of this article, loading and running tests using the NUnit GUI should be a familiar process at this point. In this section, we will take a more detailed look at two ways in which tests can be run and results generated.

NUnit GUI Application

The NUnit GUI application provides a complete, easy to use interface with which you can load, select, and view the results for unit tests. As you are already aware, loading a test assembly is as simple as selecting File | Open. Once an assembly is loaded, the nunit-gui.exe application will continue to monitor the file for changes. If you make changes in Visual Studio and re-compile, the NUnit application will re-load the assembly automatically so that it remains in sync with your development.

  1. Build the solution by selecting Build | Build Solution from the main menu.

The NUnit GUI application works with .nunit project files, so any configuration options can be tied to an assembly and saved for future use. If you take a look at the L100MathTests project again, you will notice a file named L100MathTests.nunit. This file stores NUnit project configuration data in an XML format and it is added to the project as a matter of convenience.

Follow these steps to have Visual Studio open the NUnit project file using the NUnit-Gui.exe application by default:

  1. Right-click on L100MathTests.nunit and select Open With.
  2. Select the NUnit-Gui (NUnit) program followed by the Set as Default button.
  3. Select the OK button.


Now you can load the unit tests by simply double-clicking on the .nunit project file from Solution Explorer. If NUnit fails to launch, you may need to repeat steps 2-4, but this time add a new program to the list and navigate to the nunit-gui.exe application explicitly.


You can run all tests by selecting the root node and then selecting the Run button. If tests fail to meet the assertion criteria, informative messages will be placed in the Errors and Failures tab. A red node means that not all tests passed at that node or at its descendent nodes. Green indicates that all tests passed at a node and at its descendent nodes. It is also possible to run individual test classes or even individual tests within test classes. To do so, simply select the test node that you want to run and then select Run.

NUnit test results can be saved for future use by selecting Tools | Save Results as XML from the main menu. If you select the TestAdd method and run the test, the resulting XML document will include the following information:

<test-case name="L100MathTests.MathHelperTests.TestAdd" executed="True" success="False" time="0.047" asserts="0">

<failure>

<message><![CDATA[Tested: MathHelper.Add(3, 5)

expected: <8>

but was: <0>]]></message>

    <stack-trace><![CDATA[ at L100MathTests.MathHelperTests.TestAdd() in C:L100MathLibL100MathL100MathTestsMathHelperTests.cs:line 20

]]></stack-trace>

</failure>

</test-case>

This XML tells us that the TestAdd method was executed successfully but failed to meet the conditions of an assertion. A stack trace is also provided to let us know exactly where the assertion that failed is located.

NUnit Console Application

The NUnit console application is an alternative to the GUI application that is capable of performing tests and producing XML test results. As a quick demonstration, let’s use the NUnit console application to test the L100Math library we have been working with.

  1. Load a command prompt window by selecting Start | All Programs | Accessories | Command Prompt.
  2. Change the current directory to the location where the test DLL is created by Visual Studio when built as shown below.

  1. Temporarily modify the Path environment variable to include the path to the nunit-console.exe application. Use the following command:

    path=%path%;”c:Program FilesNUnit-Net-2.0 2.2.8bin”

  1. Use the NUnit console application to test all test methods contained within the L100MathTests.dll assembly:

    nunit-console L100MathTests.dll

    Once the NUnit console application has finished running tests, failure messages are output to the console window. If you see errors here, it is an indication that you should check the results XML file for more details. By default, NUnit will create the results XML file in the same directory where you performed the tests and name it TestResult.xml.

  1. Open the TestResult.xml file generated from the last test run. You can do this from an Explorer window or by issuing the command:

    notepad TestResult.xml


The NUnit console application can also use Visual Studio project files and NUnit project files to run tests, as show in the examples below:

    Nunit-console L100MathTests.csproj

    Nunit-console L100MathTests.nunit

Many other options are available for use with the NUnit console application. Please refer to the official NUnit documentation for more information.

NUnit and the Software Design Competition

Now that you understand how to write unit tests for the NUnit framework and use the associated tools, let’s take a moment to discuss how the Software Design Competition affects the testing environment and strategy. In this section, we will highlight important points that competitors will need to keep in mind as they develop, test, submit, and debug their entries.

The design and nature of the Software Design Competition has a number of effects upon user-submitted challenge entries:

  • Entries must be optimized enough so that they can complete the tests performed on the backend before a set timeout.
  • Entries must only use code that can run under the “Execution” permission set.

For some challenges, it may be difficult to know how much optimization is necessary because the backend tests are not available to you. One solution to this problem is to simply not worry about optimization unless you get a timeout message back from the testing server. A timeout message would be something like, “Test has exceeded timeout. 3000 ms.” If you get a timeout message, you will need to examine your solution for areas that need to be optimized.

User-submitted entries will only be given the ability to execute code as defined by the .NET code access security policy. This means that you can not use file I/O, sockets, networking, or other tasks that require more privileges. One way that you can ensure your code meets this requirement during testing is to add an appropriate PermissionSet attribute to the top of your classes. The L100Math library test class, MathHelperTests, shows this in action:

[TestFixture]

[PermissionSet(SecurityAction.PermitOnly, Name = "Execution")]

    public class MathHelperTests

Note that you will need to create a unit test in order to exercise all of your code for this attribute to have any affect. A security exception will not be thrown until code is executed that tries to do something that it does not have permission to do.

The design and nature of the Software Design Competition also has a number of effects upon the test suite used on the backend, as well as the test results seen by competitors:

  • Backend tests may be more complicated than basic unit tests and use multiple objects containing multiple asserts.
  • Backend test results are returned and presented to the competitor with failure messages only – stack traces are not made available.

An ideal unit test is designed to be as simple as possible to help eliminate the possible causes for failure when the test is run. However, the Software Design Competition has a need for a consistent number of unit tests to be performed at each difficulty level. Because of this, unit tests may be more complicated than is ideal. It is important to keep in mind that if a unit test has multiple assertions in it, only the first one will be reported. As a result, a unit test may continue to fail, even as you fix individual bugs.

Competitors will only have access to the failure messages retuned from the testing backend. This will be the only diagnostic information available to you as you develop your solution to challenges. As the challenges become more difficult, the failure messages will become less helpful. For example, Level 100 tests will likely explain the exact method call and parameters that failed, whereas Level 500 tests may only mention what the test was trying to accomplish.

You may run into the following types of failure messages as you progress further into the competition:

  • Failure message that indicates a specific method failed to return the expected results.
  • Failure message that indicates a method failed with specified input values.
  • Failure message that indicates an exception occurred in a specific method.
  • Failure message that only indicates an exception occurred (no other helpful information provided).
  • Failure message due to incorrect object inheritance.
  • Failure message due to missing interface implementation.

If you are having difficulty deciphering a failure message and know which method is causing the problem, try developing your own unit tests for it to see if you can determine the root cause for the problem. You may also want to re-consult the specification provided for the challenge to see if you missed any details pertinent to the problem at hand. Remember, there is no penalty for revising your entries and re-submitting them for scoring. However, only your most recent submission counts, so regression bugs can hurt you if you’re not careful.

Debugging NUnit Tests

Once you begin to develop unit tests you may wonder, “How do I test to make sure the tests are correct?” One tool that you have available is the Visual Studio Debugger. Being able to debug the unit tests is useful since it is one of the easiest ways to exercise our library code. In this section, we will demonstrate how you can take advantage of the debugger to test your unit code.

Let’s return to the L100Math library that we were working with earlier. Make sure that you have the L100Math solution file open in Visual Studio and the MathHelperTests.cs source file open for viewing.

There are some differences between the Visual Studio Express products and the other versions of Visual Studio that necessitate two different sets of steps to demonstrate debugging. Please choose the subsection below that applies to you.

Visual Studio Express

  1. Minimize all open programs so that your desktop is visible.
  2. Right-click on the desktop and select New | Shortcut.
  3. For the location of the shortcut, use the following:

    "C:Program FilesMicrosoft Visual Studio 8SDKv2.0GuiDebugdbgclr.exe"

  1. Select Next.
  2. Use the default name for the shortcut and select Finish.

At this point, you should have a shortcut on the desktop that launches the Microsoft CLR Debugger.


  1. Ensure that the current solution is built by selecting Build | Build Solution from the main menu in Visual Studio.
  2. Double-click on the L100MathTests.nunit file in Solution Explorer to launch the NUnit GUI application.
  3. Launch the debugger from the desktop shortcut.

  1. Select File | Open | File from the main menu of the debugger. This will open the Open File dialog box.

  1. Navigate to and open the MathHelperTests.cs source file.
  2. Place a breakpoint at the first line of the TestAdd method.

  1. Select Tools | Attach To Process from the main menu of the debugger.
  2. Locate and select the nunit-gui.exe process from the list of available processes.

  1. Select Attach to attach to the NUnit GUI process. At this point, the assembly containing the TestAdd method has not been called yet, so you will see a symbol where the breakpoint was set.
  2. Switch back to the NUnit GUI application and double-click on the TestAdd method. The breakpoint that you set should be hit and the CLR Debugger application brought back to the foreground.

  1. Select Debug | Step Into from the debugger main menu to enter the MathHelper.Add method.


Now that you know how to attach to the NUnit process, the full power of the Microsoft CLR Debugger is at your fingertips.

Visual Studio Standard or higher

  1. Place a breakpoint at the first line of the TestAdd method.

  1. Right-click on the L100MathTests project in Solution Explorer and select Properties.
  2. Select the Debug tab and fill in the following options:

    Start External Program text box: C:Program FilesNUnit-Net-2.0 2.2.8binnunit-gui.exe

    Command Line Arguments text box: L100MathTests.dll

    Working Directory text box: C:L100MathLibL100MathL100MathTestsbinDebug

  1. Select Debug | Start Debugging from the main menu or use the F5 shortcut.
  2. Switch to the NUnit GUI application and double-click on the TestAdd method. The breakpoint that you previously set should be hit and a yellow cursor and line will be shown.

  1. Select Debug | Step Into from the debugger main menu to enter the MathHelper.Add method.


Now that you know how to attach to the NUnit process, the full power of the Microsoft Visual Studio Debugger is at your fingertips.

Resources & References

Here are some addition resources that you may find helpful:

NUnit project - http://nunit.org/index.php?p=documentation

Wikipedia TDD - http://en.wikipedia.org/wiki/Test-driven_development

Wikipedia unit testing - http://en.wikipedia.org/wiki/Unit_test

MSDN unit testing article - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnvs05/html/utfwvs05tmsys.asp

How to debug dll by using NUnit

Keywords: NUnit, Unit Test, Visual Studio


这里是一个精简版使用NUnit来测试一个Class Library的步骤. 这个方法比通过NUnit GUI的菜单File/Open Project方便, 因为后者在调试程序时候, 不得不在Visual Studio的Tools/Attach to Process中为Debuger绑定一个Host程序(Attach NUnit.exe). 然后才能设置断点.


或者是为VS安装UnitRun -(Resharper tool) 或TestDriven.NET 插件, 也可以很方便地在VS中直接使用NUnit进行测试.


另有一个blog更详细地说明了怎样使用NUnit.


下面的方法, 不需要任何VS插件, 却可以很方便地调试dll:(适用于 Visual Studio Standard or higher, 不适用于Express版)


1.Place a breakpoint at the first line of the TestAdd method.


2.Right-click on the L100MathTests project in Solution Explorer and select Properties.


Select the Debug tab and fill in the following options:


Start External Program text box : C:\Program Files\NUnit-Net-2.0 2.2.8\bin\nunit-gui.exe 或者 nunit.exe

Command Line Arguments text box: L100MathTests.dll

Working Directory text box: C:\L100MathLib\L100Math\L100MathTests\bin\Debug\

3. Select Debug | Start Debugging from the main menu or use the F5 shortcut.


4. Switch to the NUnit GUI application and double-click on the TestAdd method. The breakpoint that you previously set should be hit and a yellow cursor and line will be shown.

5.Select Debug | Step Into from the debugger main menu to enter the MathHelper.Add method.

Tuesday, January 22, 2008

Windows shell script programming


Keywords: Windows, shell script, bat file


There are 2 web sites, they are useful for batch program.


http://www.student.oulu.fi/~vtatila/batch_tutorial.html


http://www.computerhope.com/msdos.htm


about class library dll config file


Keywords: Class library, app configuration file


第一: 尽量不要为Class Library建立app.config文件


A dll will not have a config file, this is by design, because actually the app config file is per AppDomain while the dll did not have its own appdomain, it is loaded into the Exe's default appdomain by default.


上面的说明来自网上, 经试验, 确实不应用Visual studio 的向导为Class Library project中增加一个app config文件, 因为在dll的代码中直接使用ConfigurationManager对象是无法获取到ClassLibrary1.dll.config中的信息(假设类库为ClassLibrary1), 它所获取的是该dll的所属exe的app.config的信息.


测试实例:
下面是ClassLibrary1.dll.config的内容:



<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="key1" value="value1"/>
<add key="key2" value="value2"/>
</appSettings>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="TestConfig.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<userSettings>
<TestConfig.Properties.Settings>
<setting name="Setting1" serializeAs="String">
<value>abc</value>
</setting>
</TestConfig.Properties.Settings>
</userSettings>
</configuration>

在ClassLibrary1中读取配置文件的代码:


public string DirectUseConfigManager_In_Dll()
{
StringBuilder sb=new StringBuilder() ;
sb.Append("key1=" + ConfigurationManager.AppSettings.GetValues("key1"));
sb.Append(Environment.NewLine);
sb.Append("key2=" + ConfigurationManager.AppSettings.GetValues("key2"));
sb.Append(Environment.NewLine);
sb.Append("setting1=" + Settings.Default.Setting1);
sb.Append(Environment.NewLine);
return sb.ToString();
}

有一点需要说明的是: 如果你利用Visual Studio的Settings编辑器来编辑类库的App.config, 比如你增加了一个setting, 名为Setting1, 取值为"abc". 你也许会发现, 你的Exe项目在通过调用类库的DirectUseConfigManager_In_Dll(),可以读取到类库的app.config中的Setting1, 其实这只是一个假象. 打开类库的Settings.Designer.cs文件, 你会发现Setting1的有下面的代码.(注意第3行)


[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("abc")]
public string Setting1 {
get {
return ((string)(this["Setting1"]));
}
set {
this["Setting1"] = value;
}
}

从上面的代码可以看到, 其实Exe项目还是不能读取ClassLibrary1.dll.config文件.


第二: 怎样让ClassLibrary类库访问其app.config文件的方法.

直接用ConfigurationManager无法获取dll.config文件的原因是, ConfigurationManager确认会打开Exe的app.config文件, 如果ConfigurationManager能打开指定的配置文件, 问题就可以解决了.


在classLibrary1中通过下面代码, 就可以访问其app.config文件了.



public string UseConfigManager_OpenSpecificConfig_In_Dll()
{
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = @"ClassLibrary1.dll.config";
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
//open appSettings section
AppSettingsSection section = (AppSettingsSection)config.GetSection("appSettings");

StringBuilder sb = new StringBuilder();
sb.Append("key1=" + section.Settings["key1"].Value);
return sb.ToString();
}

handle XmlException raised when XmlDocument.Load(stream)

Keywords: System.XML.XmlDocument class, FileStream




当用一个XmlDocument对象的Load(stream)方法, 去加载一个xml文件时, 有时候会抛出"Root element is missing"这样的XmlException, 很多情况下并不是因为这个Xml文件真的缺少根节点, 或者这个xml不是well formed.


修改的方法是:将FileStream的Position属性设置为0.


if (fileStream.Length>0)


{fileStream.Position=0; //this code is necessary


xmlDocument.Load(fileStream) ;


}

Friday, January 18, 2008

SQL Executing Monitor code


Keywords: C#, Sql Execute Listener


This is a Text_Log_Tracer of SQL Execution.





using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Diagnostics;


namespace WindowsApplication2
{
/// <summary>
/// This is a Text_Log_Tracer of SQL Execute.
/// </summary>
class SqlExecuteTracer : IDisposable
{
#region Fields
private readonly string m_ErrorLogFileSuffix = "SqlError.txt";
private readonly string m_SqlLogFileSuffix = "SqlLog.txt";
private string m_ErrorLogFile;
private string m_SqlLogFile;
private TextWriterTraceListener m_SqlLogListener;
private bool m_LogSqlExecute = false;
#endregion


#region Property
/// <summary>
/// Determine whether or not log Sql statement execution
/// </summary>
/// <remarks>This is a switch for method of TraceSqlToLog()</remarks>
public bool LogSqlExecute
{
get { return m_LogSqlExecute; }
set
{
m_LogSqlExecute = value;
if (m_LogSqlExecute)
{
if (m_SqlLogListener == null)
m_SqlLogListener = new TextWriterTraceListener(m_SqlLogFile);
}
}
}
#endregion


#region Private methods

private string GetAssemblyFileWithoutExt()
{
//C:\Documents and Settings\ctsuser\My Documents\SharpDevelop Projects\asdf\bin\Debug\asdf.exe
string AssemblyFile = System.Reflection.Assembly.GetExecutingAssembly().Location;

return System.IO.Path.GetDirectoryName(AssemblyFile)
+ System.IO.Path.DirectorySeparatorChar
+ System.IO.Path.GetFileNameWithoutExtension(AssemblyFile);
}

/*
private string GetSqlFromCommand(SqlCommand cmd)
{
string sql = cmd.CommandText;
if (cmd.Parameters.Count > 0)
{
DelphiStrList strList = new DelphiStrList();
foreach (SqlParameter pmt in cmd.Parameters)
{
strList.Add(pmt.ParameterName + "=" + pmt.Value.ToString());
}
sql = sql + Environment.NewLine;
sql = sql + strList.MakeItemsToText(Environment.NewLine);
}

return sql;
}
*/
private string GetSqlFromCommand(IDbCommand cmd)
{
string sql = cmd.CommandText;
if (cmd.Parameters.Count > 0)
{
SortedList<string, string> strList = new SortedList<string, string>();
//DelphiStrList strList = new DelphiStrList();
foreach (IDbDataParameter pmt in cmd.Parameters)
{
if (pmt.Value != null)
strList.Add(pmt.ParameterName,"="+pmt.Value.ToString()) ;
//strList.Add(pmt.ParameterName + "=" + pmt.Value.ToString());
else
strList.Add(pmt.ParameterName,"=NULL") ;
//strList.Add(pmt.ParameterName + "=NULL");

}
sql = sql + Environment.NewLine;

///sql = sql + strList.MakeItemsToText(Environment.NewLine);
}


return sql;
}


private void TraceSqlToLogListener(string sql, string ErrorInfo, TraceListener listener)
{
listener.WriteLine("===================================");
listener.WriteLine(DateTime.Now.ToString());
if (String.IsNullOrEmpty(ErrorInfo) == false)
{
listener.WriteLine("Error Info:");
listener.WriteLine(ErrorInfo);
listener.WriteLine("SQL:");
}
listener.WriteLine(sql);
listener.WriteLine("===================================");
listener.WriteLine("");
listener.Flush();
}


#endregion


#region Public methods
public SqlExecuteTracer()
{
string assemblyFileWithoutExt = GetAssemblyFileWithoutExt();
m_ErrorLogFile = assemblyFileWithoutExt + "_" + m_ErrorLogFileSuffix;
m_SqlLogFile = assemblyFileWithoutExt + "_" + m_SqlLogFileSuffix;
}



public void TraceErrorSqlToLog(string sql, string ErrorMessage)
{
using (TraceListener listener = new TextWriterTraceListener(m_ErrorLogFile))
{
TraceSqlToLogListener(sql, ErrorMessage, listener);
listener.Close();
}
}



public void TraceErrorSqlToLog(IDbCommand cmd, string ErrorMessage)
{
using (TraceListener listener = new TextWriterTraceListener(m_ErrorLogFile))
{
string sql = GetSqlFromCommand(cmd);
TraceSqlToLogListener(sql, ErrorMessage, listener);
listener.Close();
}
}


public void TraceSqlToLog(string sql)
{
if (m_LogSqlExecute == false)
return;
TraceSqlToLogListener(sql, null, m_SqlLogListener);
}



public void TraceSqlToLog(IDbCommand cmd)
{
if (m_LogSqlExecute == false)
return;

string sql = GetSqlFromCommand(cmd);
TraceSqlToLogListener(sql, null, m_SqlLogListener);
}

#endregion


#region implementation IDisposable

private bool disposed = false;

public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);

}

private void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if (!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
//if (disposing)
//{
// // Dispose managed resources.
// component.Dispose();
//}

// Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.
if (m_LogSqlExecute)
m_SqlLogListener.Close();
}
disposed = true;
}


#endregion
}
}