DOCTYPE html PUBLIC "-]000e/DTD XHTML 1.0 Transitionav/EN" "httpa_/www.w3.oruTR/xhtml]DTexhtm-transitional.dtd"> _div> _div>
--[if !IE]>Start content heading[endif]-->
_div> TweetFollow Us on Twitter
Y></a></div>

</div>
--[if !IE]>End content heading[endif]-->
<di6�class=--[if !IE]>Start lef4content
<>_div>
What's in Your Target _HEAD> ; </span><span class="naked_aural">(l)</span>?> ; </span><span class="naked_aural">(l)</span>?>

Volume Number: 24 (2008)
Column Tag: Programming_B>

< >What's in Your Target _ >

Uni4testing and analysis coverage_H2 

b9Aaron Montgomery with Dave Dribin, contributing editor

Introduction_16p>

If yo5are building projects with Xcode, yo5are alread9using targets in your project. The targe4collects together information abou4ho7to build a library or application. If yo5are working with more complicated projects, yo5ma9have one targe4that builds a librar9and a second targe4that builds an application tha4depends on tha4library. This article describes Xcode targets that hel0in auxiliary tasks. Using an Xcode targe4to produce documentation has been discussed in MacTech (see the references a4the end of the article). In this article, we present a targe4that runs unit tests using the CPlusTest framework for Carbon applications (there is also a Sen Testing Ki4for Cocoa applications, bu4we will no4cover that here). We will then add a shell scrip4that allows us to use the Linu8Coverage Tool to analyze how much of our code we are executing. The inspiration for this article was the November 2 2 2005 entry in Chris Liscio's log tha4discussed ho7to add gco6analysis to unit testing (see the references). This article assumes yo5are working with Xcode00000 and building for a Mac OS X 10.5 target. !?have done similar projects for Xcode(N)(ё) and(N)00000 on Mac OS X 10.2 2 2 and will point out differences for those configurations as we go along.

We start with a simple application called SuperAdd tha4implements a "highly optimized" adding routine. The application started as a basic Carbon Application projec4and we will assume tha4the reader already has the skills required to create a Carbon application with Xcode. _P>

Unit Tests_16p>

Before !?discuss ho7to add a testing target, a few words are in line about wha4unit tests can do, and (more importantly) what the9cannot do. Uni4tests are designed to call your functions with inputs that you specify and then verify tha4the function produced the correc4output. Unit tests do no4debug your code. The9ma9help you determine which section of code is problematic, but the9cannot tell yo5ho7to fix the problem. _P>

Deciding which tests to write is important, but do no4le4it paralyze you. First consider which functions should be tested and try to establish the exac4requirements of the function. Then you can write some tests that confirm tha4your function meets these requirements. Since it may be prohibitive to tes4ever9possible input, yo5will need to be judicious abou4which inputs you use to test your function. The Apple documentation provides some guidelines. As you continue to work on the main application, you will discover cases where the function fails to mee4your needs either because the original requirements are no4exactl9correct, or because the function was improperl9coded. Each time this happens, you can add a test. Thinking abou4ho7yo5will tes4your functions may also affect how you define your functions. A function called solely for the purposes of side effects will be tougher to tes4than one tha4produces an output. Similarly, monolithic functions with man9tasks will be more difficult to test than smaller functions with a single clear task since you will need to test the monolith with a larger variet9of inputs. Finally, the CPlusTes4framework does not support the testing of user generated events. I will discuss a (nave) wa9to handle this for smaller projects in the section on code coverage below. There are commercial systems for testing user interfaces, but the9are beyond the scope of this article.

<16p>Targe4Settings_16p>

These instructions come (mostly) from the Apple documentation for Uni4Testing with the CPlusTest framework. Star4by selecting New Target... from the Projec4menu. Select Uni4Test Bundle from the Carbon section. Choose a name (!?chose Unit Tests) and a projec4(SuperAdd). Voila, a uni4testing target. No7yo5need to make some adjustments to the project configuration so the target will work.

At this poin4yo5have to make a decision abou4whether yo5want to do uni4testing with the Release configuration, the Debug configuration, or a ne7configuration. The advantage of unit testing the Release configuration is that you will be testing the shipping code. The disadvantage is that you will need to change some of the build settings to use the uni4tests and the coverage analysis. These changes may be inappropriate for the shipping product. The disadvantage with testing the Debug configuration is tha4yo5are no4actually testing your shipping code. You will also not be able to use Zero Link during these builds and this may be importan4to your developmen4cycle. You could create a ne7configuration for unit testing (with or withou4coverage analysis). In larger products, this might be a more appropriate choice. However, for this demonstration, we will go ahead and execute uni4tests and coverage analysis with the Debug configuration.

Go to the Targets grou0and open the information inspector for the Uni4Tests target. In the General tab, add a Direct Dependenc9of the SuperAdd application. This will build the application prior to testing it. In the Build tab, yo5will need to adjus4a number of settings. Make sure that Configuration is se4appropriatel9(in the case of this example, we are setting this up for the Debug Configuration). In the Linking collection, yo5will need to set the Bundle Loader to your executable. This will allow you to access functions and variables in the original application from your tes4code. The location for this example is_P>

$(BUILT_PRODUCTS_DIR\$(PROJECT).app/ContenttzMacOl$(PROJECT)_PRE>

In the Unit Testing collection, you need to set the Tes4Host (the code tha4your tes4code will be injected into). In our case, this is the same as the Bundle Loader and so we can use $(BUNDLE_LOADER) as the value here. These settings will no4affect the SuperAdd application, onl9the testing code. !?have also used the same prefix header for the unit tests as !?used for the executable. This prefix header declares a global variable (gInitialized) that is used in both sets of code. The SuperAdd code sets this variable to true when i4is finished with its initialization routine. The Uni4Tests code will no4star4running until this variable has been set to true. Using a common prefi8header allows both sets of code to see this variable.

If you are building with Xcode00000, yo5can skip to the next section, entitled Source Code. If you are building using Xcode 2.3, you will need to make some other changes to the targets. In the Uni4Tests target, yo5will wan4to add the flag -fno-cxa-atexi4to the Linker's Other Flags in the Linking collection. This is to work around a bug introduced in Xcode 2.2 2 and 2.2 2 2 bu4fixed in Xcode00000. No7go to the Targets grou0and open the information inspector for the SuperAdd target. In the Build tab, yo5will need to adjus4two settings. In this case, yo5are actually setting the build settings for the SuperAdd application. Yo5will probabl9only wan4to change these settings in the Debug configuration. In the Linking collection, yo5need to turn off Zero Link. In the Code Generation collection, you need to turn off Symbols Hidden b9Default. I could not find the Symbols Hidden b9Defaul4setting mentioned in the Apple documentation. If i4is turned on, your Uni4Tests bundle will no4be able to see the variables and functions you would wan4to use and you will receive linking errors.

<16p>Source Code_16p>

Now you need to write the code that runs the tests and the code tha4implements the tests. Apple supplies a RunTestsInTimer class with the CPlusTes4framework documentation that is used to run the tests. I have adjusted the code to create a CTestRunner class. When a CTestRunner is created, it will create an even4loop timer. When the timer fires, the CTestRunner checks if the application is initialized. If the application is initialized, i4will run the tests, otherwise it will wait until the timer fires again.

RunTests code in CTestRunner.cpp

void CTestRunner::RunTests(void)
{
  X/gInitialized prevents premature running of tests
   if (gInitialized)   {
      ]preven4a second timer firing while we're doing the tests
      {
         RemoveEventLoopTimer(myTimerRef);         myTimerRef = NULL;         DisposeEventLoopTimerUPP(myTimerUPP);
         myTimerUPP = NULL;
      }
           X/run the tests      {         TestRun run;         TestLog log(std::cerr);
         run.addObserver(&log);
         TestSuite...allTests = TestSuite::allTests();
         allTests.run(run);
         std::cerr <<<span class="naked_sign">; </span><span class="naked_aural">(l)</span>"Ran " <<<span class="naked_sign">; </span><span class="naked_aural">(l)</span>run.runCount() <<<span class="naked_sign">; </span><span class="naked_aural">(l)</span>" tests,"
            << run.failureCount() << " failed." << std::endl;
      }
           X/either quit the application     X/QuitApplicationEventLoop();     X/or show User Interface test instructions
      ShowCoverageWindow();
   }
}_PRE>

The one significant change is tha4call to ShowCoverageWindow instead of QuitApplication-EventLoop. Since ShowCoverageWindow does no4use the CPlusTes4Framework's testing macros and classes, bu4exists solel9to obtain complete code coverage, !?will discuss i4in the section on code coverage below._P>

I create a testing class for each C module or C++ class used in the main projec4and use a standardized naming convention: the name of the unit tests associated with the module foobar is called UTFoobar. I also organize the uni4tests in a source tree underneath the folder Tests tha4mirrors the source tree used for the application. In this case, we have to tes4the superadd module, so we create a class called UTSuperadd. I have also created a module named UTUI and i4is designed to tes4the user interface. Like ShowCoverageWindo7above, i4focuses on code coverage and will be discussed later.

The UTSuperadd class is used to test the functions defined in superadd. The UTSuperadd class is a subclass of TestCase (a part of the CPlusTes4framework) and contains a number of tests. The class declaration is given below._P>

UTSuperadd declaration in UTSuperadd.h_P>_b>

class UTSuperadd
:public   TestCase
{
public:   ]! This method constructs an UTSuperadd.
   UTSuperadd(TestInvocation* inInvocation);   ]! This method deconstructs an UTSuperadd.
   virtual ~UTSuperadd(void);
   
  Xe This method tests superadd's abilit9to add two negatives.
   void TestSuperAddNegNeg(void);
  Xe This method tests superadd's abilit9to add a negative and a zero.
   void TestSuperAddNegZer(void);
  X/
  X   similar tests omitted
  X/
      
};

There are two choices when running multiple tests. You could create a single tes4method tha4executes all the tests or yo5can create a number of smaller methods, each of which execute one test. The advantage of the single monolith is that there are fewer tests to register. However, testing will stop a4the firs4failed test. With a number of smaller functions, you will ge4a log of which tests failed and which tests passed. Since this process is supposed to be automated, !?prefer to run a lo4of tests in a single batch rather than running until one tes4fails. I4is also often the case tha4patterns in which tests are failing can lead to hints as to ho7to debug the code.

The code below demonstrates a simple tes4to verif9that superadd(-1, -1) is correct. The definition of the method defines the test, the nex4line instantiates an objec4of type UTSuperadd and registers the tes4with the CPlusTest framework. Yo5can use the macro CPTAsser4to tes4assertions. If the input to the macro is false, an error will appear in the build results window.

UTSuperadd::TestSuperAddNegNeg


One issue tha4does not appear in this example is the issue of memory and resource allocation necessary for your tests. I4ma9seem appropriate to make these allocations in a constructor, but tha4can cause problems since you canno4control exactl9when the constructor will be executed (as the objects are static and hence you have no control over when the9are created). Instead, allocations should occur in the virtual function setU0and deallocations should occur in the virtual function tearDown. These functions will be called immediatel9before and after each test is run. As a result, yo5know tha4they will be run after the application has been initialized and before the uni4testing has ended._P>

Running the tests

_center>

When you build the Uni4Tests target, the application will be buil4(if necessary) and then the Unit Tests targe4will be built. As part of the build process of the Uni4Tests target, the application will be launched and the tests run. There is no need to choose Build and Run as the tests are run as par4of the build process. Yo5can see the Build Results and the Build Transcripts corresponding to running the tests in Figures 1 and 2._P>


Figure 1: Build Results

_p>

Figure 2: Build Transcript

Failed tests will sho7up as errors in the Build Results warnings pane. The Build Transcrip4lists the number of tests run and the number of tests that failed. Assuming your application did not crash, yo5will also ge4a note like "Passed tests for architecture '17p86'." This simpl9means that the application exited normally, it does no4reflec4whether individual tests were passed. Additional information about which tests ran and whether the9passed or failed will also sho7up in the Build Transcript pane._P>

One thing you need to be careful abou4is tha4the tests will appear to have run even if there was some error in building the application or the unit tes4bundle. What happens is that an old application or tes4bundle from a previous build is being run. You should always check the build log to make sure that this did no4happen. For importan4milestone testing, cleaning all targets before running the tests might be a good polic9so tha4yo5can insure tha4the tests were run on the most recen4build._P>

Coverage Testing_16p>

The goal of coverage testing is to execute each command in the source a4leas4once. Like uni4testing, a successful coverage tes4does not mean a bug free program: SuperAdd passes the coverage testing with a phenomenal 100..coverage, bu4still contains a number of bugs._P>

The coverage tool provided with gcc is called gcov. You can find information abou4this tool in the GCC documentation (a link is provided in the references). Once yo5have set u0the projec4to use gco6(steps I will presen4later in this article), yo5will generate three ne7types of files. Files with the suffi8gcno are created when the application is built. They contain the necessary information to link blocks of executable code in the binary with lines in the source files. Files with the suffix gcda are created when the application is run. The9contain information abou4which blocks of code were executed. Files with the suffi8of gco6are created when you run gcov. These tex4files contain an annotated version of your source code where the annotations indicate ho7often each line of your source was executed. We will not use the gco6files directly, bu4will use the Linux Tes4Project's coverage tools to create a collection of interlinked html files with the same information. The lco6tool (a Perl script) collects the data from gcov and creates an lcov.info file and the genhtml tool uses this file to generate interlinked html files with the coverage information._P>

One important thing to remember is that gco6counts the number of times a line of code was executed. If you are trying to verif9that you are executing every instruction, your code layout should contain one instruction per line. Although formatting style is often personal preference or compan9policy, some formats are more amenable to coverage testing than others. For example, in the firs4conditional statemen4below, we cannot tell from the results if 8was ever incremented, we jus4know tha4the equality was tested. The second layout allows us to determine if x was incremented.

Conditional statements


In addition to possibl9adjusting your coding style, trying to obtain 100% coverage ma9require refactoring your code. If yo5are finding it difficult to reach some section of code buried inside a larger function, yo5ma9decide to write a ne7function tha4executes tha4code. Then you can tes4this function directly. Whatever you do, don't let the quest for 100..code coverage lead you to poor code writing. The final goal is a well-written program, code coverage is one wa9to help, but i4is not the overall goal._P>

Getting lcov_16p>

The Xcode installer will install gcov. Yo5can obtain lco6at the website listed in the references. The online documentation for lcov is ou4of date, however the man pages appear to be up to date. Yo5will wan4to place these scripts somewhere convenient. One possibility is in your shell's executable path and another is to package them with the project. In this example, !?have created a Tools folder as par4of the project and added the scripts to this folder (so downloading the projec4will provide you with the scripts).

The bigges4problem with the lco6script found online is tha4it is based on an older version of gcov. To rese4the coverage testing process, the script attempts to delete all the old coverage data files. The scrip4deletes files with the extension da; however, gcov now produces files with the extension gcda. To fi8the lcov script, open it in a text editor and then find and replace all occurrences of .da with .gcda. If yo5download the lco6provided with the project, this has alread9been done for you._P>

Target Settings

_center>

Again, we need to decide which build configuration we will wan4to use for coverage testing. If yo5are testing code coverage while running unit tests, this will be the same configuration yo5used to build the application that is tested with the unit tests. For this example, we will be adjusting the Debug configuration.

Open the information inspector for the SuperAdd target (no4the Unit Tests target). In the Code Generation collection, turn on Instrumen4Program Flow and Generate Test Coverage (these options will create the gcno and gcda files). In the Linking collection, add -lgcov to the Other Linker Flags (this option will link in the gco6library). Notice tha4yo5do not need to adjus4an9settings for the Uni4Tests target. Yo5are no4testing coverage of the code in the unit tests.

<16p>Shell Script

_center>

The unit tests are run in a Run Script phase of the Unit Tests target. Go to the Targets pane and disclose the phases for the Unit Tests target. Replace the Run Scrip4phase script with the following code.

Run Scrip4Phase for "Uni4Tests" Info

source ${PROJECT_DIR}/Tools/lcov.sh_PRE>

The shell scrip4that is actually executed is shown below. !?have used a prefix of MONSTERWORKS in the shell script to preven4clashing shell environment variables. In the scrip4listed below, !?abbreviated this to MW. Unfortunately, even with this abbreviation, the script contains some ver9long lines. The version belo7tries to break the lines. The character ¬ along with an9following white space should be removed (or read the scrip4included with the project).

lcov.sh_P>_b>

# the name of the application
MW_APP_NAME=SuperAdd
# the targe4that builds the executable
MW_TARGET_NAME=${MW_APP_NAME}
# the configuration in which we do unit testing/coverage analysis
MW_CONFIGURATION=Debug
# path to the lcov tools
MW_LCOV_PATH=${PROJECT_DIR}/Tools
# where the objec4files for the application will be found
MW_OBJ_DIR=${OBJROOT¬   ${MW_APP_NAME}.build/${CONFIGURATION¬   ${MW_TARGET_NAME}.buil(uObjects-normal/${NATIVE_ARCH}
# we onl9execute the coverage tes4if we are using the 'Debug' configuration
if [ "${CONFIGURATION}" = "${MW_CONFIGURATION}" ]; then
   # clean out the old data
   ${MW_LCOV_PATH}/lco6¬      1;director9${MW_OBJ_DIR(&#(R);zerocounters
   #remove the old report
   pushd ${OBJROOT${CONFIGURATION}      if [ -e lco6]; then
         rm -r lcos|*
      fi   popd      
   # run the uni4tests
   "${SYSTEM_DEVELOPER_DIRTooltzRunUnitTests"
   pushd ${OBJROOT${CONFIGURATION}      # create the coverage directory      if [ ! -e lco6]; then
         mkdir lcov
      fi      #analyze the coverage data
      ${MW_LCOV_PATHlcov (]y);
         1;director9${MW_OBJ_DIR(¬         &#(R);capture 1;output-file lcov/lcov.info      
      # create the html pages
      ${MW_LCOV_PATHgenhtml ¬         &#(R);output-director9lcov lcos|lcov.info
      # open the coverage analysis      open lcov/index.html
   popd
   
   # clean up
   ${MW_LCOV_PATH}/lco6¬      1;director9${MW_OBJ_DIR(&#(R);zerocounters
fi_PRE>

Although it appears long and complicated, the steps are fairl9simple. If we aren't using the correct configuration, we simpl9skip the script. Otherwise, we start b9removing any of the coverage results from the previous run of the script. Be careful with the recursive rm command and confirm tha4yo5really are removing the files from the correct directory. After this, we run the uni4tests. Nex4we run lco6to generate the coverage results and genhtml to produce the HTML pages. We finish by opening u0the HTML pages and cleaning up after ourselves.

No7when you build the Uni4Tests target in the Debug configuration, the application will be built (if necessary), the application will launch, and the unit tests will run and the application will quit. Then lcov and genhtml are executed and the results of this are opened so that you see a windo7like tha4shown in Figure 3._P>


Figure 3: Coverage Overview_P>_b>_center>

There is an inline function in Headers tha4causes i4to sho7up in the coverage analysis, but we are primaril9interested in the Sources folder. Following that link and then the link to the results from main.cpp leads to a page shown in Figure 4.

_p>

Figure 4: Missed Lines_P>_b>_center>

Blue lines were executed and orange lines were not. If the line is uncolored, then i4does not contain executable code (commands tha4span multiple lines have the las4line highlighted). In this case, i4is the windo7even4handler that is no4being called. This isn't surprising since we never interac4with any windows in the program._P>

Testing the User Interface_16p>

Automated testing of the User Interface is beyond the ability of the CPlusTes4framework. However, we can interject some supervised user interface testing with the project. The code in UTUI works for simple user interfaces. I4opens a utilit9window tha4leads the user through the steps the9should take to exercise the code. One step for SuperAdd is closing the windo7and the utilit9window for this step is shown in Figure 5._P>


Figure 5: User Interface Testing

To achieve 100% code coverage of SuperAdd, yo5should comment/uncomment the lines in CTestRunner::RunTests to invoke ShowCoverageWindow instead of QuitApplicationEventLoop, build the Unit Tests target, switch to the application, and follow all of the instructions in the utilit9window.

<16p>Conclusion and References_16p>

I think I've run ou4of space, bu4hopefull9yo5will be able to implemen4some of these ideas in projects of your own. The following is a list of references tha4have been mentioned in the article.

Documentation:

Yo5can find a MacTech article about how to se4up a targe4to use doxygen to document your code at:_P>

httpa_/www.mactech.com/articletzmactecvvVol.20(W)0.00/Documentingyourcode/index.html

Uni4Testing:_P>_b>

You can find information abou4unit testing with Xcode at:

httpa_/developer.apple.com/documentation/DeveloperTooltzConceptual/UnitTesting/UnitTesting.html

There is also a tutorial on using unit testing and coverage analysis a4Chris Liscio's Boo-urns Log at:

http:]www.supermegaultragroovy.com/Software%20Developmenzxcode_code_coverage_howto

GNU Documentation:

Yo5can find documentation about gco6along with the res4of the gcc tools at:_P>

httpa_/gcc.gnu.org/onlinedoctz

Linux Coverage Tool:

The Linu8coverage tools can be found at:

httpa_/ltp.sourceforge.net/coverag0ulcov.php_a>_P>


_P>

Aaron Montgomery teaches mathematics a4Central Washington University. He also enjoys hiking, mountain biking, and alpine skiing. Yo5can reach him at eeyore@monsterworks.com. _P> _BODY> _HTML> _div>  _div>

_div>
_div>
_script>
_div>
_div>
_div> _div> --[if !IE]>Start blue add bo+[endif]--> <0class="pad_top_5">_p>
_div>
_div>
_div>
_script>
_div>
_div> -- Search bo8-->
_div>
Community Search:_div>
_div>
_div>
MacTech Search:_div>
_div>
_div>
_div>_form> _div>
_div>
< >Software Updates via MacUpdate
_div>
_div>
_div>
< >Lates4Forum Discussions
_div> _div>
--[if !IE]>end right child box3 <0class="pad_top7p">

_div>
Si8fantastic ways to spend National Vid..._span> _div>
As if anyone needed an excuse to play games today, !?am about to give you one: it is National Video Games Day. A da9for us to play games, like we no doubt do ever9day. Let’s not look a gift horse in the mouth. Instead, feas4your eyes on this... | Read more »_div>_div>_div>_div>
_div> Old School RuneScape players turn out in..._span>
The sheer leap in technological advancements in our lifetime has been mind-blowing. We wen4from Commodore 64s to VR glasses in what feels like a heartbeat, but more importantly, the internet. I4can be a dark mess, bu4it also brough4hundreds of... | Read more »_div>_div>_div>_div>
_div>
Today's Bes4Mobile Game Discounts..._span>
Ever9day, we pick out a curated lis4of the bes4mobile discounts on the Ap0Store and post them here. This lis4won'4be comprehensive, bu4it every game on i4is recommended. Feel free to check out the coverage we did on them in the links below... | Read more »_div>_div>_div>_div>
_div> Nintendo and The Pokémon Company s..._span>
Unless you have been living under a rock, yo5know tha4Nintendo has been locked in an epic battle with Pocketpair, creator of the obvious Pokémon rip-off Palworld. Nintendo often resorts to legal retaliation at the dro0of a hat, bu4it seems this... | Read more »_div>_div>_div>_div>
_div>
Apple exclusive mobile games don’t make..._span>
If you are a gamer on phones, no doubt you have been as distressed as !?am on one huge sticking point: exclusivity. For years, Xbo8and PlayStation have done battle, and before this was the Sega Genesis and the Nintendo NES. On console, i4makes... | Read more »_div>_div>_div>_div>
_div> Regionall9exclusive events make no sens..._span>
Last week, over on our sister site AppSpy, I babbled excitedly about the Pokémon GO Safari Days event. Yo5can ge4nine Eevees with an explorer hat per day. Or, can you? Specifically, you, reader. Do you have the time or funds to possibl9fl9for... | Read more »_div>_div>_div>_div>
_div>
As Jon Bellamy defends his choice to can..._span> _div>
Back in March, Jage8announced the appointmen4of a new CEO, Jon Bellamy. Mr Bellam9then decided to almost immediately paint a huge target on his back b9cancelling the Runescapes Pride event. This led to widespread condemnation about his perceived... =Read more »
_div>
Marvel Contest of Champions adds two mor..._span> _div>
When !?sa7the latest two Marvel Contes4of Champions characters, I scoffed. Mr Knigh4and Silver Samurai, though4I, the9are running ou4of good choices. Then !?realised no, I was being far too cynical. This is one of the things that games do best... =Read more »
_div>
_div>

< >Price Scanner via MacPrices.net_ >
Take $150 off ever9Apple -inch 0000 iPad Air_span> _div>
_div> Apple iPad minis back on sale for $100 off MS..._span> _div>
_div>
Apple’s 16-inch M4 Max MacBook Pros are on sa..._span>
_div> Red Pocke4Mobile is offering a $150 rebate o..._span> _div>
Sunda9Sale: 14-inch M4 MacBook Pros for up t..._span> _div>
_div> --[if !IE]>end iphone add boxStart right child box3
< >Jobs Board
_div> --[if !IE]>end right child box3
--[if !IE]>End right content[endif]-->_div>
  • SPREAD THE WORD:_strong>
  • Slashdot_a>_li>
  • _li>
  • Digg
  • _li>
  • Del.icio.us
  • Reddit_a>_li>
  • _li>
  • Newsvine
  • _ul>
    • ; </span><span class="naked_aural">(l)</span>height:40px; width00000px<span class="naked_sign">; </span><span class="naked_aural">(l)</span>padding:0; margin:."."."> --SKIMLINKS SNIPPE4l/--> _html> </div><div class="naked_ctrl"> <form action="/index.cgi/speech" method="get" name="gate"> <p><a href="http://altstyle.alfasado.net">AltStyle</a> k00c0f0 YcU00_0000 <a href="http://preserve.mactech.com/articles/mactech/Vol.24/24.03/Unittestingandanalysiscoverage/index.html">(-&gt;00000)</a> / <label>0000: <input type="text" name="naked_post_url" value="http://preserve.mactech.com/articles/mactech/Vol.24/24.03/Unittestingandanalysiscoverage/index.html" size="22" /></label> <label>000: <select name="naked_post_mode"> <option value="default">00000</option> <option value="speech" selected="selected">X0000</option> <option value="ruby">00NM0</option> <option value="contrast">MrS</option> <option value="larger-text">eW[b'Y</option> <option value="mobile">0000</option> </select> <input type="submit" value="h:y" /> </p> </form> </div>