docs/develop: Mass directory restructure.

Now vaguely follows the tree structure of "src", with the exception of
directories that described subsystems spanning more than one "kit" or
"server" (e.g. "media", "midi", "bluetooth") -- these have been left as their
own top-level directory within docs/develop.
This commit is contained in:
Augustin Cavalier
2018-01-10 16:12:14 -05:00
parent cdf0ad6a80
commit e81a954787
60 changed files with 0 additions and 0 deletions
@@ -0,0 +1,660 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>BPicture specifications</title>
<meta http-equiv="content-type"
content="text/html; charset=ISO-8859-1">
<meta name="author" content="Marc Flerackers([email protected])">
<meta name="description"
content="BPicture specifications for OpenBeOS">
</head>
<body>
<span style="font-weight: bold; text-decoration: underline;"></span>Author:
Marc Flerackers<br>
Revision: 1.4<br>
<span style="font-weight: bold; text-decoration: underline;"></span><span
style="font-weight: bold; text-decoration: underline;"><br>
Picture data</span><br>
<br>
The data of a BPicture is composed of instructions.<br>
<br>
These instructions have a small header, which looks as follows:<br>
<br>
<table cellpadding="2" cellspacing="2" border="1"
style="text-align: left;">
<tbody>
<tr>
<td>int16</td>
<td valign="top">id</td>
<td valign="top">The instruction id</td>
</tr>
<tr>
<td valign="top">int32</td>
<td valign="top">size</td>
<td valign="top">The size of the data</td>
</tr>
</tbody>
</table>
<br>
After this header the data follows. There are two exceptions:
EnterStateChange and EnterFontState. These are used to enclose state and
font changes. For ExitStateChange and ExitFontState there are no
instructions, this is not needed as we know the size of the instruction
block in the header of the Enter* functions.<br>
<br>
These are the known instructions at the moment:<br>
<br>
<table cellpadding="2" cellspacing="2" border="1"
style="text-align: left; width: 100%;">
<tbody>
<tr>
<th valign="top">Id<br>
</th>
<th valign="top">Name<br>
</th>
<th valign="top">Size<br>
</th>
<th valign="top">Data<br>
</th>
</tr>
<tr>
<td valign="top">0x0010<br>
</td>
<td valign="top">MovePenBy<br>
</td>
<td valign="top">4<br>
</td>
<td valign="top">BPoint where<br>
</td>
</tr>
<tr>
<td valign="top">0x0100<br>
</td>
<td valign="top">StrokeLine<br>
</td>
<td valign="top">16<br>
</td>
<td valign="top">BPoint start<br>
BPoint end<br>
</td>
</tr>
<tr>
<td valign="top">0x0101<br>
</td>
<td valign="top">StrokeRect<br>
</td>
<td valign="top">16<br>
</td>
<td valign="top">BRect rect<br>
</td>
</tr>
<tr>
<td valign="top">0x0102<br>
</td>
<td valign="top">FillRect<br>
</td>
<td valign="top">16<br>
</td>
<td valign="top">BRect rect<br>
</td>
</tr>
<tr>
<td valign="top">0x0103<br>
</td>
<td valign="top">StrokeRoundRect<br>
</td>
<td valign="top">24</td>
<td valign="top">BRect rect<br>
BPoint radii<br>
</td>
</tr>
<tr>
<td valign="top">0x0104<br>
</td>
<td valign="top">FillRoundRect</td>
<td valign="top">24<br>
</td>
<td valign="top">BRect rect<br>
BPoint radii</td>
</tr>
<tr>
<td valign="top">0x0105<br>
</td>
<td valign="top">StrokeBezier<br>
</td>
<td valign="top">32<br>
</td>
<td valign="top">BPoint[4] control</td>
</tr>
<tr>
<td valign="top">0x0106<br>
</td>
<td valign="top">FillBezier<br>
</td>
<td valign="top">32<br>
</td>
<td valign="top">BPoint[4] control</td>
</tr>
<tr>
<td valign="top">0x010B<br>
</td>
<td valign="top">StrokePolygon<br>
</td>
<td valign="top">4 + point data size + 1<br>
</td>
<td valign="top">int32 numPoints<br>
BPoint *points<br>
bool isClosed<br>
</td>
</tr>
<tr>
<td valign="top">0x010C<br>
</td>
<td valign="top">FillPolygon<br>
</td>
<td valign="top">4 + point data size </td>
<td valign="top">int32 numPoints<br>
BPoint *points<br>
</td>
</tr>
<tr>
<td valign="top">0x010D<br>
</td>
<td valign="top">StrokeShape<br>
</td>
<td valign="top">shape data size<br>
</td>
<td valign="top">shape data, see below </td>
</tr>
<tr>
<td valign="top">0x010E </td>
<td valign="top">FillShape </td>
<td valign="top">shape data size </td>
<td valign="top">shape data, see below </td>
</tr>
<tr>
<td valign="top">0x010F<br>
</td>
<td valign="top">DrawString<br>
</td>
<td valign="top">4 + string data size + 8<br>
</td>
<td valign="top">strlen<br>
char *string<br>
float deltax<br>
float deltay<br>
</td>
</tr>
<tr>
<td valign="top">0x0110 </td>
<td valign="top">DrawPixels<br>
</td>
<td valign="top">56 + pixel data size<br>
</td>
<td valign="top">BRect src<br>
BRect dest<br>
int32 width<br>
int32 height<br>
int32 bytesPerRow<br>
int32 pixelFormat<br>
int32 flags<br>
int32 length of pixel data<br>
pixel data<br>
</td>
</tr>
<tr>
<td valign="top">0x0112<br>
</td>
<td valign="top">DrawPicture<br>
</td>
<td valign="top">12<br>
</td>
<td valign="top">BPoint where?<br>
????<br>
</td>
</tr>
<tr>
<td valign="top">0x0113</td>
<td valign="top">StrokeArc<br>
</td>
<td valign="top">24<br>
</td>
<td valign="top">BPoint center<br>
BPoint radii<br>
float startTheta<br>
float arcTheta<br>
</td>
</tr>
<tr>
<td valign="top">0x0114<br>
</td>
<td valign="top">FillArc<br>
</td>
<td valign="top">24<br>
</td>
<td valign="top">BPoint center<br>
BPoint radii<br>
float startTheta<br>
float arcTheta</td>
</tr>
<tr>
<td valign="top">0x0115<br>
</td>
<td valign="top">StrokeEllipse<br>
</td>
<td valign="top">16<br>
</td>
<td valign="top">BRect rect<br>
</td>
</tr>
<tr>
<td valign="top">0x0116</td>
<td valign="top">FillEllipse</td>
<td valign="top">16<br>
</td>
<td valign="top">BRect rect</td>
</tr>
<tr>
<td valign="top">0x0200<br>
</td>
<td valign="top">EnterStateChange<br>
</td>
<td valign="top">size of state instructions<br>
</td>
<td valign="top">state instructions</td>
</tr>
<tr>
<td valign="top">0x0201</td>
<td valign="top">SetClippingRects</td>
<td valign="top">16 + size of rects<br>
</td>
<td valign="top">clipping_rect bound<br>
clipping_rect *rect</td>
</tr>
<tr>
<td valign="top">0x0202</td>
<td valign="top">ClipToPicture</td>
<td valign="top">7 + 8 + 1 </td>
<td valign="top">zero bytes<br>
BPoint pt<br>
bool clip_to_inverse_picture<br>
</td>
</tr>
<tr>
<td valign="top">0x0203<br>
</td>
<td valign="top">PushState<br>
</td>
<td valign="top">0<br>
</td>
<td valign="top"><br>
</td>
</tr>
<tr>
<td valign="top">0x0204</td>
<td valign="top">PopState</td>
<td valign="top">0<br>
</td>
<td valign="top"><br>
</td>
</tr>
<tr>
<td valign="top">0x0205<br>
</td>
<td valign="top">SetClippingRects </td>
<td valign="top">0 </td>
<td valign="top">This is a shorter instruction for 0 clipping
rects.<br>
</td>
</tr>
<tr>
<td valign="top">0x0300<br>
</td>
<td valign="top">SetOrigin<br>
</td>
<td valign="top">8<br>
</td>
<td valign="top">BPoint pt<br>
</td>
</tr>
<tr>
<td valign="top">0x0301<br>
</td>
<td valign="top">SetPenLocation<br>
</td>
<td valign="top">8<br>
</td>
<td valign="top">BPoint pt<br>
</td>
</tr>
<tr>
<td valign="top">0x0302<br>
</td>
<td valign="top">SetDrawingMode<br>
</td>
<td valign="top">2<br>
</td>
<td valign="top">drawing_mode mode<br>
</td>
</tr>
<tr>
<td valign="top">0x0303</td>
<td valign="top">SetLineMode<br>
</td>
<td valign="top">2 + 2 + 4<br>
</td>
<td valign="top">cap_mode capMode<br>
join_mode joinMode<br>
float miterLimit<br>
</td>
</tr>
<tr>
<td valign="top">0x0304<br>
</td>
<td valign="top">SetPenSize</td>
<td valign="top">4<br>
</td>
<td valign="top">float size<br>
</td>
</tr>
<tr>
<td valign="top">0x0305<br>
</td>
<td valign="top">SetScale<br>
</td>
<td valign="top">4<br>
</td>
<td valign="top">float scale</td>
</tr>
<tr>
<td valign="top">0x0306<br>
</td>
<td valign="top">SetForeColor<br>
</td>
<td valign="top">4<br>
</td>
<td valign="top">rgb_color color<br>
</td>
</tr>
<tr>
<td valign="top">0x0307<br>
</td>
<td valign="top">SetBackColor<br>
</td>
<td valign="top">4<br>
</td>
<td valign="top">rgb_color color</td>
</tr>
<tr>
<td valign="top">0x0308<br>
</td>
<td valign="top">SetStipplePattern<br>
</td>
<td valign="top">8<br>
</td>
<td valign="top">pattern p<br>
</td>
</tr>
<tr>
<td valign="top">0x0309<br>
</td>
<td valign="top">EnterFontState<br>
</td>
<td valign="top">size of font instructions</td>
<td valign="top">font instructions</td>
</tr>
<tr>
<td valign="top">0x030A<br>
</td>
<td valign="top">SetBlendingMode<br>
</td>
<td valign="top">4<br>
</td>
<td valign="top">source_alpha alphaSrcMode<br>
alpha_function alphaFncMode<br>
</td>
</tr>
<tr>
<td valign="top">0x0380<br>
</td>
<td valign="top">SetFontFamily<br>
</td>
<td valign="top">4 + string data size</td>
<td valign="top">strlen<br>
char *family<br>
</td>
</tr>
<tr>
<td valign="top">0x0381<br>
</td>
<td valign="top">SetFontStyle<br>
</td>
<td valign="top">4 + string data size</td>
<td valign="top">strlen<br>
char style</td>
</tr>
<tr>
<td valign="top">0x0382<br>
</td>
<td valign="top">SetFontSpacing<br>
</td>
<td valign="top">4<br>
</td>
<td valign="top">int32 spacing<br>
</td>
</tr>
<tr>
<td valign="top">0x0383<br>
</td>
<td valign="top">SetFontEncoding<br>
</td>
<td valign="top">4<br>
</td>
<td valign="top">int32 encoding<br>
</td>
</tr>
<tr>
<td valign="top">0x0384<br>
</td>
<td valign="top">SetFontFlags<br>
</td>
<td valign="top">4<br>
</td>
<td valign="top">int32 flags<br>
</td>
</tr>
<tr>
<td valign="top">0x0385<br>
</td>
<td valign="top">SetFontSize<br>
</td>
<td valign="top">4<br>
</td>
<td valign="top">float size<br>
</td>
</tr>
<tr>
<td valign="top">0x0386<br>
</td>
<td valign="top">SetFontRotate<br>
</td>
<td valign="top">4<br>
</td>
<td valign="top">float rotation<br>
</td>
</tr>
<tr>
<td valign="top">0x0387<br>
</td>
<td valign="top">SetFontShear<br>
</td>
<td valign="top">4<br>
</td>
<td valign="top">float shear(is 0 instead of 90?)<br>
</td>
</tr>
<tr>
<td valign="top">0x0389<br>
</td>
<td valign="top">SetFontFace<br>
</td>
<td valign="top">4<br>
</td>
<td valign="top">int32 flags<br>
</td>
</tr>
</tbody>
</table>
<br>
There are a few undocumented instructions:<br>
<br>
<table cellpadding="2" cellspacing="2" border="1"
style="text-align: left;" width="100%">
<tbody>
<tr>
<td valign="top">0x0388<br>
</td>
<td valign="top">SetFontBPP </td>
<td valign="top">4<br>
</td>
<td valign="top"> int32 bpp (default 8)<br>
</td>
</tr>
</tbody>
</table>
<br>
Not all instructions where checked yet. The SetClippingRects has still
to be documented.<br>
<br>
DrawPicture and ClipToPicture have an index to the sub-picture. In
flattened data, these sub-pictures are stored in front of the main
picture data, when archived to a BMessage, the sub-pictures are
contained in a field called "piclib".<br>
<br>
<span style="font-weight: bold; text-decoration: underline;">Shape data</span><br>
<br>
The shape data contained in a BPicture is stored as follows:<br>
<br>
<table cellpadding="2" cellspacing="2" border="1"
style="text-align: left;" width="100%">
<tbody>
<tr>
<td valign="top">int32<br>
</td>
<td valign="top">instruction count<br>
</td>
</tr>
<tr>
<td valign="top" rowspan="1" colspan="1">uint32 *instructions<br>
</td>
<td valign="top" rowspan="1" colspan="1">Each instruction looks
like:<br>
First byte is the instruction id<br>
The next three bytes is the amount of points used*<br>
</td>
</tr>
<tr>
</tr>
<tr>
<td valign="top">int32<br>
</td>
<td valign="top">point count<br>
</td>
</tr>
<tr>
<td valign="top">BPoint *points </td>
<td valign="top">points<br>
</td>
</tr>
</tbody>
</table>
<br>
<table cellpadding="2" cellspacing="2" border="1"
style="text-align: left; width: 100%;">
<tbody>
<tr>
<th valign="top">Id<br>
</th>
<th valign="top">Name<br>
</th>
<th valign="top">Points*<br>
</th>
<th valign="top">Notes<br>
</th>
</tr>
<tr>
<td valign="top">0x80</td>
<td valign="top">MoveTo</td>
<td valign="top"><br>
</td>
<td valign="top">
<ul>
<li>A "MoveTo" instruction doesn't stand alone, but is OR-ed
with a "LineTo" or "BezierTo" instruction<br>
</li>
</ul>
</td>
</tr>
<tr>
<td valign="top">0x10 </td>
<td valign="top">LineTo</td>
<td valign="top">point count in instruction<br>
</td>
<td valign="top">
<ul>
<li>One "LineTo" instruction draws "count" lines</li>
</ul>
</td>
</tr>
<tr>
<td valign="top">0x90 </td>
<td valign="top">MoveTo LineTo</td>
<td valign="top">point count in instruction + 1</td>
<td valign="top">
<ul>
<li>There is one extra point for the "MoveTo", which is not
counted in the instruction.<br>
</li>
</ul>
</td>
</tr>
<tr>
<td valign="top">0x20 </td>
<td valign="top">BezierTo</td>
<td valign="top">point count in instruction</td>
<td valign="top">
<ul>
<li>One "BezierTo" instruction draws "count" lines</li>
</ul>
</td>
</tr>
<tr>
<td valign="top">0xA0 </td>
<td valign="top">MoveTo&nbsp;BezierTo</td>
<td valign="top">point count in instruction + 1</td>
<td valign="top">
<ul>
<li>There is one extra point for the "MoveTo", which is not
counted in the instruction.<br>
</li>
</ul>
</td>
</tr>
<tr>
<td valign="top">0x40 </td>
<td valign="top">Close</td>
<td valign="top">0 </td>
<td valign="top">
<ul>
<li>"Close" can only follow a "LineTo" or "BezierTo" instruction</li>
<li>If an instruction follows "Close", the new instruction is
OR-ed with "Close" and replaces it instruction</li>
<li>A&nbsp;shape never starts with "Close"</li>
</ul>
</td>
</tr>
</tbody>
</table>
<br>
</body>
</html>
@@ -0,0 +1,34 @@
Tests executed on a Duron 1200
ikki:~/projects/current# tests/UnitTester BRegion
------------------------------------------------------------------------------
Tests
------------------------------------------------------------------------------
BRegion::Construction Test
+ PASSED
Clock time: 0 ms
BRegion::Exclude Test
+ PASSED
Clock time: 251 ms
BRegion::Include Test
+ PASSED
Clock time: 260 ms
BRegion::Intersect Test
+ PASSED
Clock time: 102 ms
BRegion::OffsetBy Test
+ PASSED
Clock time: 0 ms
------------------------------------------------------------------------------
Results
------------------------------------------------------------------------------
+ PASSED
As you can see, it may be worth optimizing especially the Exclude and Include methods.
See RegionSupport.cpp (in particular RSub() and ROr()) for more info.
@@ -0,0 +1,30 @@
Tests executed on a Duron 1200
ikki:~/projects/current# tests/UnitTester -r5 BRegion
------------------------------------------------------------------------------
Tests
------------------------------------------------------------------------------
BRegion::Construction Test
+ PASSED
Clock time: 0 ms
BRegion::Exclude Test
+ PASSED
Clock time: 284 ms
BRegion::Include Test
+ PASSED
Clock time: 265 ms
BRegion::Intersect Test
+ PASSED
Clock time: 113 ms
BRegion::OffsetBy Test
+ PASSED
Clock time: 0 ms
------------------------------------------------------------------------------
Results
------------------------------------------------------------------------------
+ PASSED
@@ -0,0 +1,391 @@
<HTML>
<!-- $Id: UnitTestingInfo.html 10 2002-07-09 12:24:59Z ejakowatz $ -->
<HEAD>
<TITLE>Unit Testing Information</TITLE>
</HEAD>
<BODY BGCOLOR="white" LINK="#000067" VLINK="#000067" ALINK="#0000FF">
<FONT FACE="Verdana,Arial,Helvetica,sans-serif" SIZE="-1">
<H1>Unit Testing Information:</H1>
<P>This document describes the "why's" and "how's" of unit testing for the AppKit team of the
OpenBeOS project. Although it is intended for the AppKit team, there is no reason other teams
couldn't use this information to develop a similar unit testing strategy.</P>
<P>The document has the following sections:</P>
<OL>
<LI><A HREF="#what">What is unit testing?</A></LI>
<LI><A HREF="#why">Why is unit testing important?</A></LI>
<LI><A HREF="#when">When should I write my unit tests?</A></LI>
<LI><A HREF="#whattests">What kinds of tests should be in a unit test?</A></LI>
<LI><A HREF="#testframework">What framework is being used to do unit testing for the AppKit?</A></LI>
<LI><A HREF="#frameworkmods">What AppKit specific modifications have been made to this framework?</A></LI>
<LI><A HREF="#futuremods">What framework modifications might be required in the future?</A></LI>
<LI><A HREF="#buildingtests">How do I build the framework and current tests for the AppKit?</A></LI>
<LI><A HREF="#runningtests">How do I run tests?</A></LI>
<LI><A HREF="#writingtests">How do I write tests for my component?</A></LI>
<LI><A HREF="#exampletests">Are there example tests to base mine on?</A></LI>
<LI><A HREF="#threadedtests">How do I write a test with multiple threads?</A></LI>
</OL>
<A NAME="what"></A><H2>What is unit testing?</H2>
<P>Unit testing is the process of showing that a part of a software system works as far as the
requirements created for that part of the system. Unit testing is best if it has the following
characteristics:</P>
<UL>
<LI>The software component is tested in isolation with as little interaction with other software
components as possible.</LI>
<LI>The software component is tested using automated tools so that unit tests can be run with
every build of the software if required.</LI>
<LI>All requirements of the software component are tested as part of the unit tests.</LI>
</UL>
<P>Unit testing is not the only type of testing but is definitely a very important part of any
testing strategy. Following unit testing, software should go through "integration testing" to
show that the components work as expected when put together.</P>
<A NAME="why"></A><H2>Why is unit testing important?</H2>
<P>A basic concept of software engineering is that the cost of fixing a bug goes up by a factor
of 2-10x (depending on the source of the information) the later in the development process it is
found. Unit testing is critical to finding implementation bugs within a particular component as
quickly as possible.</P>
<P>Unit testing will also help to find requirements problems also. If you write the requirements
(or use cases) for your component from the BeBook, hopefully the BeBook and your use cases will
match the actual Be implementation. A good way to confirm that the BeBook documentation matches
Be's implementation is to write your unit tests and run them against the original Be code.</P>
<P>Unit tests will also continue to be maintained and run in the future also. As the mailing
lists obviously show, many people are looking forward to OpenBeOS post-R1 when new features
will be introduced above and beyond BeOS R5. These unit tests will be critical to ensuring that
any new feature or even just a bug fix doesn't break existing functionality.</P>
<P>Speaking of bug fixes, consider adding unit tests for any bugs you identify that slipped
through your original unit test suite. This will ensure that this bug or a similar one is not
re-introduced in the future.</P>
<P>Finally, unit testing is not the be all, end all of testing. As mentioned above, integration
testing must be done to show that software components work together. If all unit tests cover
all requirements and have run successfully against all components, then a failure has to be
due to a bug in the interaction of two or more known working software components.</P>
<A NAME="when"></A><H2>When should I write my unit tests?</H2></LI>
<P>As the AppKit process document describes the recommended order for implementing a component
is:</P>
<OL>
<LI>Write an interface specification</LI>
<LI>Write the use case specifications</LI>
<LI>Write the unit tests</LI>
<LI>Write an implementation plan</LI>
<LI>Write the code</LI>
</OL>
<P>Please see the AppKit process document for more details about the entire sequence. The unit
test are to be written once the use cases are written and before any implementation work is
done. The use cases must be done because they determine what the tests will be. You need to
write as many tests are required so that all use cases for that component are tested. The use
cases should be detailed enough that you can write your unit tests from them.</P>
<P>The unit tests are to be done before implementation for a very good reason. You should be able
to run these unit tests against the Be implementation and confirm that they all pass. If they do
not pass, then either there is a bug in the unit test itself or you have found a difference
between your use cases and the actual implementation. Even if your use cases match the BeBook,
if that is not how the actual Be implementation works, we must match the current implementation and
not the BeBook. You should go back and modify the use case. Change the use case so that it
matches Be's implementation and consider adding a note indicating this doesn't match the
BeBook.</P>
<P>Imagine if you completed the implementation and then wrote and ran the unit tests. If you run
the tests against your implementation and Be's implementation, you will notice the test passes
for your code but fails on Be's. At this point, you will have to change the implementation, change
the unit test and change the use case which is more work that if you write the unit tests before
the implementation. Worse, if you only ran the unit tests against your implementation and not
Be's, you may not notice the problem at all.</P>
<A NAME="whattest"></A><H2>What kinds of tests should be in a unit test?</H2>
<P>The unit tests you write should cover all the functionality of your software module. That
means your unit tests should include:</P>
<UL>
<LI>All standard expected functionality of the software component</LI>
<LI>All error conditions handled by the software component</LI>
<LI>Interaction with software components which cannot be decoupled from the target software
component</LI>
<LI>Concurrency tests to show that a software component which is expected to be thread safe (most
things are under BeOS) is safe and free from deadlocks.</LI>
</UL>
<A NAME="testframework"></A><H2>What framework is being used to do unit testing for the AppKit?</H2>
<P>The AppKit team has chosen to use CppUnit version 1.5 as the basis of all of our unit tests.
This framework provides very useful features and ensures that all unit tests for AppKit code
are consistent and can be executed from a single environment.</P>
<P>There are two key components to the framework. First, there is a library called libCppUnit.so
which provides all the C++ classes for defining your own testcases. Secondly, there is an
executable called "TestRunner" which is capable of executing a set of testcases.</P>
<P>For more information on CppUnit, please refer to
<A HREF="http://cppunit.sourceforge.net/">this website</A>
<A NAME="frameworkmods"></A><H2>What AppKit specific modifications have been made to this framework?</H2>
<P>The following are the modifications that have been introduced into the CppUnit v1.5
framework:</P>
<UL>
<LI>A makefile has been added for the library and the TestRunner.</LI>
<LI>Some "bugs" in CppUnit v1.5 which lead to it not compiling under BeOS v5.</LI>
<LI>The TestRunner has been modified to support BeOS based addons. Each test which you can
select from the TestRunner is found in the "add-ons" directory at runtime. The original
TestRunner required you to change the TestRunner when new tests were added to it.</LI>
<LI>Changed the output from TestRunner. The output includes a name of the test being run and
a run time for the test in microseconds.</LI>
<LI>Changed the arguments of the assert functions in the TestCase class from std::string to
const char *'s due to apparent concurrency problems with std::string under BeOS when testing
threaded tests.</LI>
<LI>Added locking to the TestResults class so that multiple threads can safely add result
information at the same time for a single test.</LI>
<LI>The ThreadedTestCaller class was written to allow us to write tests which contain multiple
threads. This is an important class because many BeOS components are thread safe and we need
to confirm that the OpenBeOS implementation is also thread safe.</LI>
</UL>
<P>This is the list of the important modifications done to CppUnit v1.5 at the time this document
is being written. For the latest information about modifications to CppUnit, check the code
which can be found in the OpenBeOS CVS repository.</P>
<A NAME="futuremods"></A><H2>What framework modifications might be required in the future?</H2>
<P>This framework will have to evolve as our needs grow. The main issues I think we need to
solve are:</P>
<UL>
<LI>The format of the test name is an encoded string representing the class definition of the
test class from gcc. It is not a very readable format but given that the test class is often
a template class and you would like different names for different instances of the template,
this seemed the best compromise. Suggestions welcome.</LI>
<LI>The threaded test support added into CppUnit forces you to specify the entry point for each
thread in your test. If you are doing a test with a BLooper or a BWindow, these classes start
a thread of their own. This thread will not be started through the standard entry point so
doing "assert's" from one of these threads will not work. Perhaps we need TestBLooper and
TestBWindow classes which will work with the assert's.</LI>
</UL>
<P>If you find you need some other features, feel free to add them to CppUnit.</P>
<A NAME="buildingtests"></A><H2>How do I build the framework and current tests for the AppKit?</H2>
<P>As of writing this document, you can build the framework and all the current AppKit tests
by performing the following steps:</P>
<OL>
<LI>Checkout the "app_kit" sources or the entire repository from the OpenBeOS CVS repository.
There is information at the OpenBeOS site about how to access the CVS repository.</LI>
<LI>In a terminal, "cd" into the "app_kit" directory in the CVS files you checked out.</LI>
<LI>Type "make".</LI>
</OL>
<P>Note that the build system for OpenBeOS is moving to jam so these steps may become obsolete.
When you the make has finished, you should find the following files:</P>
<UL>
<LI><CODE>app_kit/test/CppUnit/TestRunner</CODE> - this is the executable to use to execute
tests.</LI>
<LI><CODE>app_kit/test/CppUnit/lib/libCppUnit.so</CODE> - this is CppUnit library which your tests
must link against.</LI>
<LI><CODE>app_kit/test/CppUnit/lib/libopenbeos.so</CODE> - this is library which contains OpenBeOS
implementation of some Be classes (usually found in libbe.so, called libopenbeos.so to avoid a name
clash at runtime).</LI>
<LI><CODE>app_kit/test/add-ons/BAutolockTests</CODE> - this is the addon which contains the tests
which are run against the Be and OpenBeOS implementation of BAutolock.</LI>
<LI><CODE>app_kit/test/add-ons/BLockerTests</CODE> - this is the addon which contains the tests
which are run against the Be and OpenBeOS implementation of BLocker.</LI>
<LI><CODE>app_kit/test/add-ons/BMessageQueueTests</CODE> - this is the addon which contains the tests
which are run against the Be and OpenBeOS implementation of BMessageQueue.</LI>
</UL>
<P>These are the key files which ensure that the tests can be run.</P>
<A NAME="runningtests"></A><H2>How do I run tests?</H2>
<P>You have a few different options for how you run a test or a series of tests. Before you start
however, you must build the code as describe <A HREF="#buildingtests">in this section</A>. Once
it is built, you can run tests any of these ways:</P>
<UL>
<LI>Run "make test" from the app_kit directory. This will lead to all of the tests defined in
app_kit/test/add-ons directory to be run.</LI>
<LI>From the "app_kit/test" directory, execute the command "CppUnit/TestRunner -all". This will
lead to all of the tests defined in the app_kit/test/add-ons directory to be run and is the same
as what happens in the "make" example above. However, recompile any code that has changed in the
process.</LI>
<LI>From the "app_kit/test" directory, execute the command "CppUnit/TestRunner &lt;TestName&gt;"
where &lt;TestName&gt; is one of the addons found in the "app_kit/test/add-ons" directory. Only
the tests defined in that add-on will be run.</LI>
</UL>
<A NAME="writingtests"></A><H2>How do I write tests for my component?</H2>
<P>The first step to writing your tests is to develop a plan for how you will test the
functionality. For ideas of the kinds of tests you may want to consider, you should reference
<A HREF="#whattests">this section</A>.</P>
<P>Once you know the kinds of tests you want, you need to:</P>
<UL>
<LI><P>For every test you want, define a class which derives from the "TestCase" class in the
CppUnit framework.</P></LI>
<LI><P>Within each test class you define, create a "void setUp(void)" and "void tearDown(void)"
member function if required. If before executing your test, you need to perform some actions,
put those actions in the "setUp()" member. If you need to cleanup after your test, put those
actions in the "tearDown()" member.</P></LI>
<LI><P>Within each test class you define, create a member function which takes "void" and
returns "void". Within this member function, write the code to execute the test. Whenever you
want to ensure that some condition is true during your test, add a line within the member function
that looks like "assert(condition)". For example, if the variable "result" must have the value
B_OK at a particular point in your test, you should add a line which reads
"assert(result = B_OK)".</P></LI>
<LI><P>Create a constructor for all of your test classes that takes a "std::string name" argument
and pass that onto the TestCase parent class. Add whatever actions you need to take in the
constructor.</P></LI>
<LI><P>Create a destructor for all of your test classes and take whatever actions are
appropriate.</P></LI>
<LI><P>Within each test class you define, create a member with the signature
"static Test *suite(void)". For a simple test where only one test needs to be run for this class,
the contents of this member should look like:</P>
<PRE>
return(new TestCaller&lt;ClassName&gt;("", &amp;ClassName::MemberName));
</PRE>
<P>Replace "ClassName" with the name of your test class and "MemberName" with the name
of the member function you defined your test in. If you need to define more than one test to run
from this class, refer to instructions below on how to use the TestSuite class of CppUnit. If you
are creating a threaded test, refer to <A HREF="#threadedtests">this section</A>.</P></LI>
<LI><P>Create one ".cpp" file for defining the "addonTestFunc()" function. This function must
exist in global scope within your test addon. The contents of this ".cpp" file will look something
like:</P>
<PRE>
#include "TestAddon.h"
Test *addonTestFunc(void)
{
TestSuite *testSuite = new TestSuite("&lt;TestSuiteName&gt;");
testSuite-&gt;addTest(&lt;ClassName1&gt;::suite());
testSuite-&gt;addTest(&lt;ClassName2&gt;::suite());
/* etc */
return(testSuite);
}
</PRE>
<P>In the above example, replace &lt;TestSuiteName&gt; with an appropriate name for the group of
tests and &lt;ClassName1&gt; and &lt;ClassName2&gt; with the names of the test classes you have
defined.</P></LI>
<LI><P>Create a build system around a BeIDE project, Makefile or preferrably a jam file which
builds all the necessary code you have written into an addon.</P></LI>
<LI><P>Put this addon into the app_kit/test/add-ons directory and follow the above instructions
for how to run your tests.</P></LI>
</UL>
<A NAME="exampletests"></A><H2>Are there example tests to base mine on?</H2>
<P>There are example tests which you can find in the following directories:</P>
<UL>
<LI><CODE>app_kit/test/lib/application/BMessageQueue</CODE></LI>
<LI><CODE>app_kit/test/lib/support/BAutolock</CODE></LI>
<LI><CODE>app_kit/test/lib/support/BLocker</CODE></LI>
</UL>
<P>There are some things done in these tests which make things a bit more complex, but you may
want to do similar things:</P>
<UL>
<LI>Most tests use a ThreadedTestCaller class even in some situations when there aren't actually
more than one thread in the test.</LI>
<LI>All tests are defined as a template class. The test class is a template of the class to test
(if that makes sense to you). For example, to test both the Be and OpenBeOS BLocker and not
end up with a symbol conflict, the OpenBeOS implementation of BLocker is actually in a namespace
called "OpenBeOS". So, the tests must be run against the classes "::BLocker" and
"OpenBeOS::BLocker". The easiest way to do this was to make the class to be tested a template
and define it for both "::BLocker" and "OpenBeOS::BLocker".</LI>
</UL>
<P>Even with the complexity, I think this code provides a pretty good example of how to write
your tests.</P>
<A NAME="threadedtests"></A><H2>How do I write a test with multiple threads?</H2>
<P>If you have a test which you want to define that requires more than one thread of execution
(most likely a concurrency test of you code), you need to use the ThreadedTestCaller class.
The steps which differ from the above description on how to write a test case are:</P>
<UL>
<LI><P>In your test class, define a member function for each thread you will be starting. All of
these member functions must take "void" and return "void". If all the threads in your test
perform the exact same actions, it is OK to just define one member function. Usually in the
tests I have written, I have called these member functions "TestThread1()", "TestThread2()",
etc.</P></LI>
<LI><P>If your "static Test *suite()" function for your test class, you must return a
ThreadedTestCaller. Imagine that the test class name is "MyTestClass" and you want two threads
which run member functions "TestThread1()" and "TestThread2()". That code would look like:</P>
<PRE>
Test *MyTestClass::suite(void)
{
MyTestClass *theTest = new MyTestClass("");
ThreadedTestCaller&lt;MyTestClass&gt; *threadedTest = new TreadedTestCaller&lt;MyTestClass&gt;("", theTest);
threadedTest-&gt;addThread(":Thread1", &amp;MyTestClass::TestThread1);
threadedTest-&gt;addThread(":Thread2", &amp;MyTestClass::TestThread2);
return(threadedTest);
}
</PRE>
<P>If you need to, you can put a number of ThreadedTestCaller instances into a TestSuite and return
them in the suite() member function. Examples of this can be found in the BLocker and
BMessageQueue test examples.</P></LI>
</UL>
<P>Otherwise the steps are the same as for other tests. The code gets much more complex if you
define your test classes as templates as the examples do.</P>
</FONT>
</BODY>
</HTML>
@@ -0,0 +1,341 @@
<HTML>
<!-- $Id: BDeskbarUseCases.html 1185 2002-09-26 02:21:31Z jrand $ -->
<HEAD>
<TITLE>BDeskbar Use Cases and Implementation Details</TITLE>
</HEAD>
<BODY BGCOLOR="white" LINK="#000067" VLINK="#000067" ALINK="#0000FF">
<FONT FACE="Verdana,Arial,Helvetica,sans-serif" SIZE="-1">
<H1>BDeskbar Use Cases and Implementation Details:</H1>
<P>This document describes the BDeskbar interface and some basics of how it is implemented.
The document has the following sections:</P>
<OL>
<LI><A HREF="#interface">BDeskbar Interface</A></LI>
<LI><A HREF="#usecases">BDeskbar Use Cases</A></LI>
<LI><A HREF="#implement">BDeskbar Implementation</A></LI>
</OL>
<A NAME="interface"></A><H2>BDeskbar Interface:</H2>
<P>The BDeskbar class is a simple class for getting information from the deskbar and for modifying
it from your application. The best source of source of information for the BDeskbar interface can be found
<A HREF="file:///boot/beos/documentation/Be%20Book/Deskbar/Deskbar.html">here in the Be Book</A>.
</P>
<A NAME="usecases"></A><H2>BDeskbar Use Cases:</H2>
<P>The following use cases cover the BDeskbar functionality:</P>
<OL>
<LI><P><B>Construction:</B> A BDeskbar does not take any arguments when it is constructed. The
BDeskbar instance creates a connection to the deskbar in order to get and change its state.</P></LI>
<LI><P><B>Destruction:</B> When a BDeskbar is deconstructed, the application's connection to the
deskbar is closed. However any change to the deskbar's state made through the BDeskbar instance
persists.</P></LI>
<LI><P><B>Add Item 1:</B> The AddItem() member function can be used to take a passed in pointer to
a BView and send it to the deskbar for inclusion in its shelf. This BView must be archivable
and must be exported by the application (for details on how to do this,
<A HREF="http://bedriven.be-in.org/articles/replicant/III_027-stepping%20up%20to%20the%20deskbar.html">this article</A>
may help). The item will be added and the id of the new item will be passed back to the caller
through a pointer to an int32.</P></LI>
<LI><P><B>Add Item 2:</B> The AddItem() member function can be used to add an item to the deskbar
shelf by passing a pointer to an entry_ref. The file pointed to by this entry_ref should be
an addon that exports the symbol "BView *instantiate_deskbar_item()". This entry point is used to
get a BView which it can display in the shelf. More information on this mechanism can be found in
the <A HREF="file:///boot/beos/documentation/Be%20Book/Release%20Notes/Deskbar.html">Deskbar Release Notes</A>
but not in the Be Book proper. The item id of the added item is passed back in an int32 pointer
provided by the caller. NOTE: The source code for the deskbar found in
<A HREF="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/opentracker/opentracker/deskbar/StatusView.cpp?rev=1.5&content-type=text/vnd.viewcvs-markup">TReplicantTray::LoadAddon()</A>
indicates that it also looks for a symbol called "BView *instantiate_deskbar_entry(image_id, entry_ref *)"
first, but there is no documentation on this.</P></LI>
<LI><P><B>Remove Item 1:</B> The RemoveItem() member function takes an integer id and removes it
from the deskbar shelf if it exists. The member returns B_OK at all times (unless the deskbar is
not running or some communication failure occurs). A B_OK result does not mean that an item was
actually removed.</P></LI>
<LI><P><B>Remove Item 2:</B> The RemoveItem() member function also takes a string name and removes
it from the deskbar shelf if it exists. The member returns B_OK at all times (unless the deskbar is
not running or some communication failure occurs). A B_OK result does not mean that an item was
actually removed.</P></LI>
<LI><P><B>Count Items:</B> The CountItems() member function takes no arguments. It returns the
number of "items" in the deskbar shelf. For example, the small email icon often found in the
deskbar is one such item.</P></LI>
<LI><P><B>Has Item 1:</B> The HasItem() member function takes a integer id and returns a true or
false value which indicates whether or not an item exists in the deskbar shelf on that id. For
example, the small email icon often found in the deskbar is one such item.</P></LI>
<LI><P><B>Has Item 2:</B> The HasItem() member function also takes a string name parameter and
returns a true or false value which indicates whether or not an item by than name exists in
the deskbar shelf. For example, the small email icon often found in the deskbar is named
"mail".</P></LI>
<LI><P><B>Get Item Info 1:</B> The GetItemInfo() member function takes an integer id and a pointer
to a const char * (ie a string). It checks to see if the id passed in exists in the deskbar and
sets the value of the const char * to point to a allocated buffer which contains the name of the
item which corresponds to this id and the function returns B_OK. Ownership of this allocated
buffer is assigned to the caller of this member function so it is up to the caller to free the
memory. If the id doesn't exist, then it still returns B_OK but the pointer to the string is set
to NULL. If the pointer to the string passed in is NULL, the function returns B_BAD_VALUE.</P></LI>
<LI><P><B>Get Item Info 2:</B> The GetItemInfo() member also takes a string (const char *) name
and a pointer to an int. If the name matches an item in the deskbar shelf, the id of this
item is returned at the location pointed to by the integer pointer and the member returns B_OK.
If the name doesn't match an item in the deskbar shelf, the id is set to -1. If the pointer
passed in is NULL, the function returns B_BAD_VALUE.</P></LI>
<LI><P><B>Frame:</B> The Frame() member function returns a BRect which describes the location and
size of the deskbar on the screen.</P></LI>
<LI><P><B>Location:</B> The Location() member function returns one of B_DESKBAR_TOP,
B_DESKBAR_BOTTOM, B_DESKBAR_LEFT_BOTTOM, B_DESKBAR_RIGHT_BOTTOM, B_DESKBAR_LEFT_TOP or
B_DESKBAR_RIGHT_TOP. The return value describes where the deskbar currently is located. Also,
the Location() member function takes an optional argument which is a pointer to a boolean.
If supplied, the boolean which is pointed to is set to true if the deskbar is expanded and false
otherwise. A deskbar can only be contracted (ie not expanded) when in the left or right top
position.</P></LI>
<LI><P><B>Is Expanded:</B> The IsExpanded() member function returns true if the deskbar is
expanded and false if it is contracted. Note, the deskbar can only be contracted when in
left or right top position.</P></LI>
<LI><P><B>Set Location:</B> The SetLocation() member function takes the same values returned
by the Location() member. The value passed in the first argument sets the position of the deskbar.
If the optional second argument is supplied, it is a boolean which indicates whether or not the
deskbar is expanded (true) or contracted (false). Note, the deskbar can only be contracted when in
left or right top position.</P></LI>
<LI><P><B>Expand:</B> The Expand() member function takes a single boolean argument which sets the
deskbar to expanded (true) or contracted (false) mode. Note, the deskbar can only be contracted
when in left or right top position.</P></LI>
</OL>
<A NAME="implement"></A><H2>BDeskbar Implementation:</H2>
<P>Internally, the BDeskbar uses a BMessenger to communicate with the deskbar itself.
The source code from the OpenTracker project will be used as a reference for this effort.
You can find the deskbar source code here:</P>
<BLOCKQUOTE>
<A HREF="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/opentracker/opentracker/deskbar/">http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/opentracker/opentracker/deskbar/</A>
</BLOCKQUOTE>
<P>Specifically, the code which handles communicating with the BDeskbar class can be found
here:</P>
<BLOCKQUOTE>
<A HREF="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/opentracker/opentracker/deskbar/BarWindow.cpp?rev=1.2&content-type=text/vnd.viewcvs-markup">http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/opentracker/opentracker/deskbar/BarWindow.cpp?rev=1.2&amp;content-type=text/vnd.viewcvs-markup</A>
</BLOCKQUOTE>
<P>The following describes the messages used to communicate between BDeskbar and the deskbar
itself.</P>
<H3>AddItem:</H3>
<P>The AddItem() member sends the following message to the deskbar to add an item from an
archived BView:</P>
<PRE>
BMessage theMsg;
BMessage viewMsg;
theView.Archive(&amp;viewMsg); // This takes the target BView to place in the shelf and archives it into viewMsg
theMsg.what = 'icon'
theMsg.AddMessage("view", &amp;viewMsg); // This puts the archived view in the viewMsg and puts it in the message to the deskbar
</PRE>
<P>Or, the AddItem() member sends the following message to the deskbar to add an item from a file
that exports the "BView *instantiate_deskbar_item(void)" function:</P>
<PRE>
BMessage theMsg;
theMsg.what = 'adon'
theMsg.AddRef("addon", &amp;theAddonRef); // This is the addon which contains the hook function to get the view to add
</PRE>
<P>The /boot/app/Pulse application exports the necessary symbol for this mechanism to work and
is a good candidate to test with.</P>
<P>In either case, the deskbar responds with a message which looks like:</P>
<PRE>
BMessage theMsg;
theMsg.AddInt32("id", theID); // This is the id of the new item
</PRE>
<P>Note that in both cases, the deskbar does not set the what code of the reply. Checking the
source code for
<A href="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/opentracker/opentracker/deskbar/BarWindow.cpp?rev=1.2&content-type=text/vnd.viewcvs-markup">TBarWindow::AddItem()</A>
confirms this.
<H3>HasItem:</H3>
<P>The HasItem() member sends the following message to the deskbar:</P>
<PRE>
BMessage theMsg;
theMsg.what = 'exst'
theMsg.AddInt32("id", theID); // This is the id to check for
// OR, only one of id or name should be in the message
theMsg.AddString("name", theName); // This is the name to check for
</PRE>
<P>The deskbar responds with a message which looks like:</P>
<PRE>
BMessage theMsg;
theMsg.AddBool("exists", IDorNameExists()); // This is a true/false value which indicates whether or not the name/id exists in the shelf
</PRE>
<P>Note that the deskbar does not set the what code of the reply. Checking the source code
for
<A href="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/opentracker/opentracker/deskbar/BarWindow.cpp?rev=1.2&content-type=text/vnd.viewcvs-markup">TBarWindow::ItemExists()</A>
confirms this.</P>
<H3>GetItemInfo:</H3>
<P>The GetItemInfo() member sends the following message to the deskbar:</P>
<PRE>
BMessage theMsg;
theMsg.what = 'info'
theMsg.AddInt32("id", theID); // This is the id to check for
// OR, only one of id or name should be in the message
theMsg.AddString("name", theName); // This is the name to check for
</PRE>
<P>The deskbar responds with a message which looks like:</P>
<PRE>
BMessage theMsg;
theMsg.AddString("name", theName); // This is the name corresponding to the id of the original request
// OR, only one of id or name should be in the response message depending on the request sent
theMsg.AddInt32("id", theID); // This is the id corresponding to the name of the original request
</PRE>
<P>Note that the deskbar does not set the what code of the reply. Checking the source code
for
<A href="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/opentracker/opentracker/deskbar/BarWindow.cpp?rev=1.2&content-type=text/vnd.viewcvs-markup">TBarWindow::ItemInfo()</A>
confirms this.</P>
<H3>CountItems:</H3>
<P>The CountItems() member sends the following message to the deskbar:</P>
<PRE>
BMessage theMsg;
theMsg.what = 'cwnt'
</PRE>
<P>The deskbar responds with a message which looks like:</P>
<PRE>
BMessage theMsg;
theMsg.what = 'rply'; // This means reply
theMsg.AddInt32("count", ItemCount()); // This is the number of items in the deskbar shelf
</PRE>
<H3>RemoveItem:</H3>
<P>The RemoveItem() member sends the following message to the deskbar:</P>
<PRE>
BMessage theMsg;
theMsg.what = 'remv'
theMsg.AddInt32("id", theID); // This is the id to remove
// OR, only one of id or name should be in the message
theMsg.AddString("name", theName); // This is the name to remove
</PRE>
<P>The deskbar does not send a response.</P>
<H3>Frame:</H3>
<P>The Frame() member sends a standard scripting message to get the frame from the deskbar. It
sends a B_GET_PROPERTY message to the deskbar asking for the "Frame" property specifying the
window by name. The window name is "Deskbar".</P>
<P>The response from deskbar has a what code of B_REPLY and a BRect describing the frame in a
value called "result". This is standard BeOS scripting.</P>
<H3>Location:</H3>
<P>The Location() member sends the following message to the deskbar:</P>
<PRE>
BMessage theMsg;
theMsg.what = 'gloc'; // This means get location
</PRE>
<P>The deskbar responds with a message which looks like:</P>
<PRE>
BMessage theMsg;
theMsg.what = 'rply'; // This means reply
theMsg.AddInt32("location", DeskbarLocation()); // This is the number which represents the location of the deskbar
theMsg.AddBool("expanded", Expanded()); // This is true if the deskbar is expanded, false otherwise
</PRE>
<H3>IsExpanded:</H3>
<P>The IsExpanded() member sends the following message to the deskbar:</P>
<PRE>
BMessage theMsg;
theMsg.what = 'gexp'; // This means get expanded state
</PRE>
<P>The deskbar responds with a message which looks like:</P>
<PRE>
BMessage theMsg;
theMsg.what = 'rply'; // This means reply
theMsg.AddBool("expanded", Expanded()); // This is true if the deskbar is expanded, false otherwise
</PRE>
<H3>SetLocation:</H3>
<P>The SetLocation() member sends the following message to the deskbar:</P>
<PRE>
BMessage theMsg;
theMsg.what = 'sloc'; // This means set location
theMsg.AddInt32("location", newLocation); // This is the number which represents the location of the deskbar
theMsg.AddBool("expand", isExpanded); // This is true if the deskbar is expanded, false otherwise
</PRE>
<P>The deskbar does not send a reply to this message.</P>
<H3>Expand:</H3>
<P>The Expand() member sends the following message to the deskbar:</P>
<PRE>
BMessage theMsg;
theMsg.what = 'sexp'; // This means set expanded state
theMsg.AddBool("expand", isExpanded); // This is true if the deskbar is expanded, false otherwise
</PRE>
<P>The deskbar does not send a reply to this message.</P>
</BODY>
</HTML>
@@ -0,0 +1,89 @@
<HTML>
<!-- $Id: BPolygonUseCases.html 1727 2002-10-28 02:50:08Z jrand $ -->
<HEAD>
<TITLE>BPolygon Use Cases and Implementation Details</TITLE>
</HEAD>
<BODY BGCOLOR="white" LINK="#000067" VLINK="#000067" ALINK="#0000FF">
<FONT FACE="Verdana,Arial,Helvetica,sans-serif" SIZE="-1">
<H1>BPolygon Use Cases and Implementation Details:</H1>
<P>This document describes the BPolygon interface and some basics of how it is implemented.
The document has the following sections:</P>
<OL>
<LI><A HREF="#interface">BPolygon Interface</A></LI>
<LI><A HREF="#usecases">BPolygon Use Cases</A></LI>
<LI><A HREF="#implement">BPolygon Implementation</A></LI>
</OL>
<A NAME="interface"></A><H2>BPolygon Interface:</H2>
<P>The BPolygon class is used to hold information about a shape composed of a series of straight
lines (ie a polygon). On its own, it just describes the shape and can only be drawn by passing
it to a BView. The best source of source of information for the BPolygon interface can be found
<A HREF="file:///boot/beos/documentation/Be%20Book/The%20Interface%20Kit/Polygon.html">here in the Be Book</A>.
</P>
<A NAME="usecases"></A><H2>BPolygon Use Cases:</H2>
<P>The following use cases cover the BPolygon functionality:</P>
<OL>
<LI><P><B>Construction 1:</B> A BPolygon can be constructed without passing it any arguments. When
this is done, the polygon will have no points in it (ie no shape) until they are added through
AddPoints().</P></LI>
<LI><P><B>Construction 2:</B> A BPolygon can be constructed by passing it a pointer to an existing
BPolygon (ie a copy constructor). The resulting copy will have the exact same state as the
one passed in. That means it will have the same number of points in the same locations resulting
in the same shape.</P></LI>
<LI><P><B>Construction 3:</B> A BPolygon can be constructed by passing it a pointer to an array of
BPoints and an integer which describes the number of points in that array. The BPolygon will be
constructed such that it holds the shape described by that array of points.</P></LI>
<LI><P><B>Destruction:</B> When a BPolygon is deconstructed any memory allocated in order to hold
the state of the BPolygon is freed and the state of the polygon is lost.</P></LI>
<LI><P><B>Add Points:</B> The AddPoints() member function appends a number of passed in points to
the existing set of points already in the polygon. It takes a pointer to an array of BPoints and
an integer count of the number of points to append. This is similar to the "Construction 3" use
case except in that case there is no existing points so the passed in points describe the entire
polygon.</P></LI>
<LI><P><B>Count Points:</B> The CountPoints() member function returns the number of points which
describe the polygon. The result is an integer.</P></LI>
<LI><P><B>Frame:</B> The Frame() member function returns the smallest BRect which contains all of
the points which describes the BPolygon.</P></LI>
<LI><P><B>Map To:</B> The MapTo() member function applies a translation (ie move) and a scale (ie
grow/shrink) operation to the existing polygon, adjusting all points according to the passed in
rule. The operation to apply depends on two passed in BRect's. The translation and scale
adjustment which turns the first BRect into the second BRect is applied to all points in the
BPolygon.</P></LI>
<LI><P><B>Print To Stream:</B> The PrintToStream() member function sends the set of points which
make up the BPolygon to standard output. It does so by performing a PrintToStream() on the
individual BPoint's which make up the polygon. This member is generally used for debugging and
the output is primarily human readable and not sensitive to changes which could risk backward
compatibility.</P></LI>
<LI><P><B>Assignment Operator</B> The operator=() operator is defined for BPolygon's. It takes
a source BPolygon and assigns it to another existing BPolygon target. The state of the target
BPolygon is lost and replaced with that of the source. The source retains its state so the outcome
is two BPolygons with the same state (ie set of points).</P></LI>
</OL>
<A NAME="implement"></A><H2>BPolygon Implementation:</H2>
<P>Internally, the BPolygon contains an array of BPoint's which it uses to track the shape it
holds. The implementation of BPolygon is fairly simple since it is a fairly basic container
class for a set of points.</P>
</BODY>
</HTML>