Yesterday I started to poke around with the cxxtest testing framework.

So basically, to start right off you need:

  • Source file to test. It shouldn’t have a main function. At least if you do things the way I did which is by linking the compiled object file with the test runner object file (which defines a main function).
  • A header file which defines the actual test.
  • A Makefile that defines the rules needed to compile all of this.

Source files to test

So this is the simple source code that I am going to test (Yes I know it’s not a parser, I just named it that way, cause it’s cool):

#include "parser.hpp"

inline bool Parser::surrounded_by(const string& s, char left, char right)
{
  return s.at(0)==left && s.at(s.length()-1)==right;
}

void Parser::strip(string& s) {
  static const string filter="\r\n\t ";

  size_t right = s.find_last_not_of(filter);
  if(string::npos == right) {
    s.clear();
    return;
  }

  size_t left = s.find_first_not_of(filter);
  if(string::npos == left) left=0;

  s=s.substr(left,(right-left)+1);
}

And this is the header file:

#ifndef PARSER_HPP_
#define PARSER_HPP_

#include <string>
#include <map>

using std::map;
using std::string;

namespace Parser {
  inline bool surrounded_by(const string& s, char left, char right);
  void strip(string& s);
}
#endif

The actual test

I like things neatly tucked into directories so I made a subdir test. There I have a file named parserTest.h with the following content
Note: I don’t know why but WordPress displays the NULL character \ 0 (lines 51 and 54) as a space, so I wrote 0 instead.

#include <cxxtest/TestSuite.h>
#include "parser.hpp"
using std::string;

class ParserTestSuite : public CxxTest::TestSuite {
  public:
  void testStrip()
  {
    string s=" strip me  ";
    Parser::strip(s);
    TS_ASSERT_EQUALS(s,"strip me");
  }
  void testNoStrip()
  {
    string s="don't  strip me", s1=s;
    Parser::strip(s);
    TS_ASSERT_EQUALS(s,s1);
  }
  void testStripLeft()
  {
    string s="  left strip me";
    Parser::strip(s);
    TS_ASSERT_EQUALS(s,"left strip me");
  }
  void testStripRight()
  {
    string s="right strip me  ";
    Parser::strip(s);
    TS_ASSERT_EQUALS(s,"right strip me");
  }

  void testSurrondedBy()
  {
    const string s="?am I surronded by questionmarks?";
    TS_ASSERT( Parser::surrounded_by(s, '?', '?') );
  }
  void testNotSurroundedBy() {
    const string s="I'm the authority";
    TS_ASSERT( !Parser::surrounded_by(s, ' ', ' ') );
  }
  void testLeftOnlySurrondedBy() {
    const string s="?Left yes but right no.";
    TS_ASSERT( !Parser::surrounded_by(s, '?','!') );
  }
  void testRightOnlySurroundedBy() {
    const string s="Left no but right yes!";
    TS_ASSERT( !Parser::surrounded_by(s, '?', '!') );
  }
  void testNotSurroundedByNullChar() {
    const string s="Am I terminated by a null char? Are we all?";
    TS_ASSERT( !Parser::surrounded_by(s, 'A', 0) );
  }
  void testCStringNotSurroundedByNullChar() {
    TS_ASSERT( !Parser::surrounded_by("A C string", 'A', 0) );
  }
  void testCStringSurroundedBy() {
    TS_ASSERT( Parser::surrounded_by("! Yes !", '!', '!') );
  }

};

Of course this blog entry is just an example of how to basically use cxxtest. So you should check out the manual (html | pdf) (as always) to see much more info. Also in the cxxtest source tree there is a directory sample that holds Makefilse for different operating systems and a few basic tests. The main difference between my sample and the ones in the source code tree of cxxtest is that I have subdirectory that holds the tests, hence the Makefiile is a bit different (also, I’ve stripped some of it that I don’t need, like GUI output).

The Makefile

So, the Makefile is really important. Just put it in test/Makefile. Of course, you should edit the paths in the SHELL and TESTGEN directory. The TESTGEN variable holds the path to the Perl script that generates the test runner cpp file (called error_printer here) which is later compiled and run.

SHELL = /bin/bash
VPATH = ..:.
CXXC = g++ -Wall -I. -I..
CC = g++ -c -I. -I..
TESTGEN = /usr/bin/cxxtestgen.pl
TARGETS = error_printer
TESTS = *.h

all: $(TARGETS)
clean:
	rm -f *~ *.o *.obj $(TARGETS) $(GUI_TARGETS)
	rm -f tests.cpp error_printer.cpp
	rm -f qt_runner.cpp

distclean: clean
	rm -f Makefile

run: error_printer
	./error_printer

error_printer.cpp: $(TESTS)
	$(TESTGEN) -o $@ --error-printer $(TESTS)

stdio_printer.cpp: $(TESTS) parserTest
	$(TESTGEN) -o $@ --runner=StdioPrinter $(TESTS)

tests.cpp: $(TESTS)
	$(TESTGEN) -o $@ $(TESTS)

error_printer.o: error_printer.cpp
	$(CC) error_printer.cpp -o error_printer.o

error_printer: error_printer.o parser.o
	$(CXXC) error_printer.o parser.o -o error_printer

%: %.cpp
	$(CXXC) -o $@ $<

Now to run the tests we do
make run
in the test directory.

The output is:

[emil@lappy test]$ make run
/usr/bin/cxxtestgen.pl -o error_printer.cpp --error-printer *.h
g++ -c -I. -I.. error_printer.cpp -o error_printer.o
g++    -c -o parser.o ../parser.cpp
g++ -Wall -I. -I.. error_printer.o parser.o -o error_printer
./error_printer
Running 11 tests.........OK!

The file associations in KDE4 can be a real pain in the ass.

In System Settings → Advanced User Settings → File Associations [1] you can only set the preferred application for a certain MIME type. For example, if you wanted to change the default application used by KDE4 for editing ruby scripts, in [1] you would go to application → x-ruby. There on the right-hand side of the dialog you would probably see that Kate is the preferred application. You would be able to move gvim up to the top of the list of the associated editors for ruby scripts. After clicking the Apply button, gvim would certainly be the default editor for rb files all across KDE (except for executable rb files, which would just be executed instead of opened in an editor).

But what if you wanted to make gvim your default editor?

The closest solution, that I am aware of, to this problem is to assign a higher priority (called InitialPreference) for your preffered applications, and lower to those you don’t like that much.

This is done by editing the following file (change gvim for other applications):

$(kde4-config –prefix)/share/applications/gvim.desktop

Inside that file either change the value assigned to InitialPreference if such a line exists or add a new line. Like so:

InitialPreference=20

This would make gvim prevail on all applications with an InitialPreference lower than 20.

There is a slight problem with this however. Because assigning a higher priority to a certain program might make it preferrable for an unexpected MIME type that it associated itself with.
For example, The GIMP associates itself with PDF files. So, if you set a high priority on GIMP, this could potentially force KDE to stop opening files with Okular (or your favourite PDF viewer). So you would have to either put a higher priority on Okular or edit the PDF mimetype and put Okular on the top of the list. So you get the idea that this is not a perfect solution.

How I’d like this to be

The way that I see things in a perfect world would be to fine-grain MIME types to categories and subcategories. Then in System Settings → Advanced User Settings → Default applications you could have a wide range of application types: like text editors, image viewers, video players, etc. so you could quickly edit the default application for some categories that apply to this application type. For example, setting a default editor would immediately tell KDE to open the “plain text files and readmes”, “source files”, “log files”, “config files” or whatever categories that apply to a text editor. And you could make exceptions throughout these. You could choose gvim to be the default only for source files.
If you want you could instead still use [1].

Доста е дразнещо, когато редактирам някой файл като root, а конфигурациите, които по принцип ползвам, са недостъпни, защото са локализирани във /home/emil/.vimrc.
Това може да се реши със symlink. Като root:

mv ~/.vimrc ~/.vimrc_backup; ln -s /home/emil/.vimrc ~/.vimrc

За да работят цветови теми, плъгини и т.н.

mv ~/.vim ~/.vim_backup; ln -s /home/emil/.vim ~/.vim

Тъпото е, че още не съм го направил това :D Отивам.

Известно време се бях поотчаял какви проблеми могат да настъпят при опитите ми просто да копирам нещо от външния свят във vim. Пример:

От firefox се опитвам да копирам (със selection буфера в UNIX (да, този със средния бутон на мишката), или нормалния C-V). Vim обаче се прави на ударен. Не ще да paste-не. Обратното също е дразнещо.

Няма начин vim да не поддържа copy-paste с външния свят? Разбира се, че поддържа!

Ако не ти се чете, направо прескочи към рецептата

Регистри

И така vim предоставя така наречените регистри, които са нещо като именувани clipboards. Тоест vim има поддръжка за повече от един буфер! Можете да си ги кръщавате с букви. Например да имате a,b,c,d и да кажете на vim: copy това в a, paste тук от b, copy онова в c, paste там от c.
Регистрите са достъпни със следната комбинация в нормален режим. r е име на регистър.

"ry (copy в регистъра r)
"rp (paste от регистъра r)

Или поне това е употребата, за която знам – достатъчно важна сама по себе си.
И така, сочната част. Има два специални регистъра * и +. * отговаря на буфера, свързан обикновено със средния бутон на мишката, а + отговаря за другия (C-V). Прочетох някъде, под Windows буферите * и + не се различават.
И така, малко примери! Може да замените * със + за алтернативните буфери, разбира се.

"*y
Аналог на y (yank) – само по себе си не копира, очаква движение (motion, например с G копира всичко от текущата позиция до края на файла). Виж документацията за yank (:help yank) за подробности.

Освен с движение може да се ползва и с visual selection. Натиска се v (или V за маркиране по цели редове), след като направите селекцията, натискате

"*y

и тя е в буфера. Отивате във firefox и натискате средния бутон в някое текстово поле и готово!

"*p
Аналог на p.

Ама мързи ме да ги натискам тея “*, бе!

И двете решения не се справят с проблема при изпълняване на vim като su. Дори да направите symlink-ове към конфигурационните файл и директория, изпълняван през su, vim пак няма да има достъп до буферите на X11.

Най-лесното решение

Най простото решение е във ~/.vimrc да се сложи:

set clipboard=unnamed

Това кара vim да използва по подразбиране буфера, свързан със средния бутон под UNIX (под Windows със clipboard-a)

Другото решение

Във моя ~/.vimrc имам следното:

map . "*y
map , "*p
Редакция: Ето един добър повод да науча какво прави . във vim (срам е, че не съм го знаел, това си е основно). Както и да е, вече не ползвам . и , за copy-paste в регистри. Но може да се map-нат към други клавиши.

Разбира се, това е освен, ако не ползвате стандартните bindings на тези бутони, а именно:

,	reverse direction of last "f", "F", "t", or "T" command
.	repeat last text-changing command

Сега ползвам . за копиране на визуална селекция (за UNIX: в буфера, свързан със средния бутон – за другия буфер заменете * с +).
Забележка: ако искам да копирам цял ред например не натискам

..

както бих направил с

yy

, а вместо това:

.y Копира целия ред
.w Копира до края на думата
gg.G копира целия файл (gg движи до началото на файла, G до края му)

Въобще, като цяло

.{motion} Копира според движението (виж :help motion за подробности)

Друг вариант за ~/.vimrc е вместо . и , да се ползват каквито ви е удобно бутони (като се внимава за конфликт).

Laptop: Dell Inspiron 1525
After I updated my whole system a few days back I had no sound although my soundcard was recognized and configured. Alsa levels weren’t muted.

Fixed it by adding:

 options snd-hda-intel model=auto

to /etc/modrpobe.d/50-sound.conf.

Other options except “auto” are “toshiba” and “acer”.

Also, I had no wireless interface. My card is:

[emil@lappy ~]$ lspci | grep 802.11
0b:00.0 Network controller: Broadcom Corporation BCM4312 802.11b/g (rev 01)

I’m using ndiswrapper. It was working before the upgrade.

Fixed it by blacklisting the module ssd in /etc/rc.conf:

...
DAEMONS = (!ssd ...)
...

In result I get:

[emil@lappy ~]$ iwconfig
wlan0     IEEE 802.11g  ESSID:off/any
          Mode:Managed  Frequency:2.462 GHz  Access Point: Not-Associated
          Bit Rate:54 Mb/s   Tx-Power:32 dBm
          RTS thr:2347 B   Fragment thr:2346 B
          Power Management:off
          Link Quality:0  Signal level:0  Noise level:0
          Rx invalid nwid:0  Rx invalid crypt:0  Rx invalid frag:0
          Tx excessive retries:0  Invalid misc:0   Missed beacon:0

Now it’s all good again.

Нещата, които просто харесвам и използвам с удоволствие всеки ден:

  • Сърфирам в нета с firefox
  • Пиша код с vim
  • Ежедневни задачи с urxvt
  • Използвам ICQ с kopete (отскоро + wrapper-a за (гнусния) Skype)
  • Чета новини и блогове с blogbridge
  • Слушам музика с amarok
  • Чета книги и други pdf документи с okular
  • Гледам филми с mplayer
  • Понякога блогвам с wordpress
  • Понякога си играя с inkscape
  • Свалям торенти с ktorrent
  • Отбелязвам интересни страници с del.icio.us

Може би не е тайна, че чистотата на кода не е от приоритетните области на българските Интернет компании. И не само българските. Докато адското занемаряване на кода е донякъде разбираемо за големи проекти, които не прилагат добра методология за поддръжка и нямат добра архитектура, то за малки и прости странички това е адски тъпо и само показва неграмотността и мърлявостта на “дивелъпърите”.

Ето няколко тъпотии от HTML-a на http://sa.dir.bg – бивш онлайн речник – сега търсачка.

В резултатите от търсене в речника:

<div class="rezoltati">

Готино име, а?

document.write('<sc'+'ript type="text/javascript" ... + '"></sc'+'ript>');

Е тука без конкатенация няма как да стане ;) Абе, може и да е за няк’ва четимост т’ва, не знам, и аз съм зелен още, тъй че… може про-тата така да правят ;)

За далеч по-интересни истории от този тип, виж веднага The Daily WTF.

По принцип не използвам фунцкионалността, налична в LINUX десктоп системите, позволяваща виртуални десктопи. Тя обаче е доста удобна, ако имате наотворени много прозорци. Малко по-малко свиквам да я ползвам. Мисля, че ще ми помогне в главата си да имам логическо разделение за 4-те (това ми се струва разумен брой, по default е в KDE) работни площи. Ето как си представям въпросното разделение:

  1. Desktop #1. Файлов мениджър; отворени документи, снимки.
  2. Desktop #2. Браузъри.
  3. Desktop #3. Конзоли.
  4. Desktop #4. Плеъри; чат клиенти; други глупости.

Програмистите са различни. Както всички хора. Наблюденията ми ме накараха да измъдря тази класификация на програмистите, която може да е адски тъпа/невярна, но няма как да знам това все още. Бързам да кажа, че съм леко пристрастен и освен това, че оптимално би било всеки програмист да се стреми да бъде добре балансиран и да попада в колкото се може повече категории (с изключение на някои…), но да има и идентичност (т.е. да не попада в твърде много категории).

Ето draft-варианта.

  1. Програмистът – Geek. Обича Open Source.
    Обича да прави нещата в името на правенето им.
    Не използва интегрирани среди за разработка (IDE) – ползва добър текстов редактор – emacs/vim/textmate.
    Кефи се на книги и филми (най-вероятно фантастика)/futurama/комикси/музика.
    Обича да носи оригинални тениски с мъдрости.
    Има силно развито, но и специфично чувство за хумор.
    Обича математиките или поне има такива, които му доставят удоволствие.
    Обикновено може да пише грамотно. И код.
    Не се чувства добре в костюм.
    Не обича лъскавите места. Кефи се на задушевна атмосфера.
  2. Бизнес програмистът. Обича да печели пари, не толкова да пише код.
    Използва IDE. Носи костюм (или поне риза, вмъкната в дънките).
    Смята geek-овете за несериозни.
    Обича сложни системи, предпочита да не знае какво има под капака и да управлява нещата по-отгоре.
    Работи в голяма корпорация. Кара скъпа кола. И все пак харчи парите си умерено.
    Инвестира в разработката на собствен софтуер.
  3. Чалга програмистът. Слуша *****, обича най-популярните “фолк клубове” на София. През нощта се напива и се кърши в ритъма на “фолк” “музиката”. През деня работи в средна по големина компания. Гледа да се скътава. Носи ланец, има скъп телефон (не, не добър). Харчи по 300лв. на ден на Слънчев бряг / Златни пясъци. Често не може да пише правилно. Не му пука за това. Мечтае си за повечето неща, които бизнес програмистът постига. Знае 3 технологии. Прочел е 2 книги. Бяга от идеологии/философски идеи и теория като от чума. Не признава образованието (в България). Трябва му само диплома. Той всичко знае.
  4. Хардкор програмистът. Той може всичко. По трудния начин. Програмира микроконтролери (assembly, C). Оправя се със сложни конструкции на ниско ниво. По-хардуерен тип. Не му трябва документация, защото “този код веднъж написан, няма да се пипа”. А ако се пипа, той знае какво да прави. Ако Чък Норис беше програмист…
  5. Програмистът-състезател. Обича да решава задачи. Бързо. Не се интересува особено от добри практики. Използва глобални променливи, избягва абстракциите. Знае как да печели. Знае много алгоритми. Не знае много технологии. Харесва му да учи.
  6. Програмистът-изчислител. Работи по научни проекти. Използва числени методи. Знае доста математика. Полага къртовски труд, но знае защо го прави.
    *Програмистът-учител. Това реално не е програмист, но ще го включа “за пълнота на изложението”. Знае един език за програмиране. Вече пише код само на лист. Издава “учебници” и кара “учениците” му да ги четат. Или ги кара да четат “учебниците” на някой себеподобен. В тях няма фрагменти код. Има разпростриращи се “платна” текст на програми със смотан шрифт и лошо подравняване. Лошото е, че обикновено има и втора част. Резултат: “учениците” се депресират и се отказват от програмирането.

Много съм слаб в принтирането. Никога не разпечатвам нещо, по-дълго от една страница, от първия път. Понякога и да е една, пак оцапвам нещо. Обикновено хабя от 1.5 до 3 пъти повече хартия и мастило, отколкото е нужно.
Да не говорим за разпечатването на цели книги – особено двустранно. Направо се превръщам в убиеца на разпечатването. Но не съм изцяло аз виновен. Принтерът също се държи странно/печата грозно понякога. Например, днес трябваше да разпечатам един проект, включващ диаграми, които обаче са доста бледи.

  • Първи опит. Диаграмите са цветни, а аз нямам цветно мастило – длъжен бях да пробвам все пак.
  • Втори опит. Grayscale. Отпечатаха се първите две страници, за третата не стигна черното мастило.
  • Трети опит. Смених мастилото. Отпечатаха се две страници – на първата не се забелязваше, но на втората личеше – нищо не се разбира от диаграмите – много са бледи.
  • Четвърти опит. Приложих някои хватки в настройките на драйвера (Canon, btw). Резултат горе-долу четими диаграми. Свърши хартията, сложих още. Отпечатах докрай! КРАЙ!

Бележка: Първата страница е леко омачкана, но не ми пука – малко ли хартия похабих, че да печатам нова начална страница, заради една гънка :D