4 lipca 2014

[Notki] Praca w terminalu z tmux-em.

Bardzo fajny artykuł Łukasza Wróbla na temat pracy z tmux-em. Fajne narzędzie do podziału terminala na kilka paneli. Nie jest to wciąż coś czego poszukuje, ale na razie wystarcza:
Po wciśnięciu Ctrl+b program przechodzi do trybu kontroli. Notki:
  • Ctrl+b " - split horyzontalnie
  • Ctrl+b % - split wertykalnie
  • Ctrl+b strzałka - przełączenie między panelami
  • Ctrl+b+strzałka - zmiana rozmiaru panelu
  • Ctrl+b PgUp/PgDn - skrolowanie w panelu (aby wyłączyć ten tryb "q")

29 czerwca 2014

[python] unittest/mocks - część II

Garść informacji na temat unittest/mock, które sobie ostatnie przyswoiłem, m.in. czytają ciekawy artykuł:

Dopasowanie czegokolwiek - mock.ANY

Odpowiednik testing::_ w GoogleMock, czyli akceptowanie każdego argumentu z jakim zostanie wywołany mock, co pozwala na rozluźnienie zależności (coupling).
class Gearbox:
    def moveGear(self, gearLevel):
        print('Gear to level: ' + str(gearLevel))
Test
class TestVehicle(unittest.TestCase):

    def test_tractorStartOnRandomGear(self):
        mock_gearbox = mock.create_autospec(Gearbox)
        tractor = Vehicle(mock_gearbox)
        tractor.runEngine()
        mock_gearbox.moveGear.assert_called_once_with(mock.ANY)

Mock vs. MagicMock vs. create_autospec

Z tego co udało mi się zrozumieć MagicMock-i, różnią się od zwykłych Mock-ów tym, że posiadają predefiniowane wartości dla pewnych pospolitych metod np.: __len__ == 1.
Ponieważ mock.Mock i mock.MagicMock akceptują wołania z dowolną ilością argumentów, najlepiej korzystać mock.create_autospec. Taki mock w przypadku gdy ilość argumentów się nie zgadza rzuci wyjątek.

Dekorator @mock.patch zamiast dependency injection

Dekoratory z biblioteki mock, pozwalają na zgrabne przesłanianie klas i modułów w testowanym kodzie, dzięki czemu korzystamy z dobrodziejstw dependency injection, bez niepotrzebnego rozbudowywania "konstruktorów".

Kolejność dekoratorów jest istotna

Każdy moduł importuje inne moduły do swojej lokalnej przestrzeni, dlatego należy pamiętać, by nie mock-ować modułów (np. os) w pliku z testami (bo tylko tutaj będzie zmock-owany). Należy explicit wskazać na moduł gdzie jest nasz testowany kod (np. mycode.os).

Kiedy korzysta się z wielu dekoratorów należy pamiętać o ich kolejności. Mapowanie dekoratorów do parametrów następuje w odwrotnej kolejności niż deklaracje. Przykład poniżej.
import os
import sys

class FilesSystem:
    def countFolders(self):
        l = [dir for dir in os.listdir('.') if os.path.isdir(dir)]
        sys.exit(len(l))
Test
import unittest
import mock
import asdf

class TestFileSystem(unittest.TestCase):

    @mock.patch('asdf.os')
    @mock.patch('asdf.sys')
    def test_countFolders(self, mock_sys, mock_os):
        mock_os.listdir.return_value = ['folder1', 'folder2']
        mock_os.path.isdir.return_value = True

        fs = FilesSystem()
        fs.countFolders()

        mock_os.listdir.assert_called_once_with('.')
        expected = [call.mock_os.path.attribute.isdir('folder1'),
                    call.mock_os.path.attribute.isdir('folder2')]
        self.assertTrue(mock_os.path.isdir.mock_calls == expected)
        mock_sys.exit.assert_called_once_with(2)
Innym rodzajem dekoratora jest @mock.patch.object, który pozwala na z-mockowanie wybranej metody z klasy, gdy cała reszta nadal będzie wołała oryginalną implementację.
class Accounts:
    def isUser(self, user):
        print('isUser ' + user)

    def assign(self, user, movie):
        print('assign ' + user + ' ' + movie)
Test
class TestVideoLib(unittest.TestCase):

    @mock.patch.object(Accounts, 'isUser')
    def test_whenUserExist_thenHeCouldRentAMovie(self, mock_isUser):
        mock_isUser.return_value = True
        accounts = Accounts()
        videoLib = VideoLib(accounts)
        videoLib.rent('Jhon', 'Titanic')

        mock_isUser.assert_called_once_with('Jhon')

Otwarte kwestie: Odpowiednik StrictMock, mock-owanie metody open, list comprehension - które niekiedy sprawa mi problemy, gdy chce jest otestować.

28 czerwca 2014

[Notki] Działanie i budowanie plików dll

Notki z godzinnego podcastu Gynvaela Coldwinda odnośnie budowania oraz działania plików dll. Tutaj tylko budowanie.



Plik asdf.c.
#include <stdio.h>

__declspec(dllimport) int add(int a, int b);

int main(void) {
    printf("5+6 ==  %d\n", add(5, 6));
    return 0;
}
Biblioteka (my_dll.c) będzie udostępniać tylko jedną funkcję. __declspec nie jest konieczne, jeżeli będziemy korzystać z pliku z definicjami.
__declspec(dllexport) int add(int a, int b) {
    return a + b;
}
Plik z definicjami my_dll.def.
LIBRARY my_dll
EXPORTS
    add
    dodaj=add
Budowanie:

Najpierw kompilujemy do pliku obiektowego, następnie trzeba posłużyć się dllwrap, który jest rodzajem linkera, dla plików dll. Dodawanie pliku z definicjami nie jest obowiązkowe, przydaje się dopiero wtedy, gdy chcemy stworzyć aliasy na nasze funkcje.

dlltool pozwala na tworzenie bibliotek (dla kompilatorów) (.a), coś z czym będziemy linkować dany program. Jest to konieczne, bowiem nie każdemu kompilatorowi możemy powiedzieć, aby korzystał z dll, akurat gcc to potrafi. W tej bibliotece będzie wyłącznie informacja dla linker, że dany kod znajduje się w jakiejś dll-ce. Wymagany jest plik z definicjami exportu.
> gcc -c my_dll.c
> dllwrap my_dll.o -o my_dll.dll --def my_dll.def 
> dlltool -l libmy_dll.a -D my_dll.dll -d my_dll.def

> gcc asdf.c my_dll.dll
# alternatywne rozwiązanie z wskazaniem biblioteki libmy_dll.a 
# będzie poszukiwana w obecnym katalogu
> gcc asdf.c -L. -lmy_dll

Name mangling

Funkcje stworzone w C++, są exportowane pod innymi nazwami np. _Z4addii - udekorowane są dodatkowymi informacjami. Wynika to z faktu, że C++ pozwala na istnieje kilku funkcji o tej samej nazwie, pod warunkiem, że różnią się one przyjmowanymi typami. Aby móc w kodzie C++ skorzystać z funkcji add (funkcji C z dll) należy skorzystać z takiej deklaracji:
extern "C" {
    int add(int a, int b);
}
W odwrotnej sytuacji, gdy mamy kod w C i chcemy skorzystać z funkcji C++ w dll, trzeba posłużyć się tą udekorowaną nazwą _Z4addii.

26 maja 2014

DEF CON 21 - Ryan W Smith and Tim Strazzere - DragonLady An Investigation of SMS Fraud

Kolejny fajny wykład na DEF CON 21, tym razem ujawnia kilka faktów na temat programów afiliacyjnych przy rozprzestrzenianiu szkodliwego oprogramowania.

25 maja 2014

5 maja 2014

Flaw of Software Design

Seria krótkich wykładów Maxa Kanata-Alexandera, dotycząca problemów jakie pojawiają się podczas tworzenia oprogramowania:
  • Writing Code that isn't Needed
  • Zasada podobna do YAGNI (You aren't gonna need it), czyli nie tworzenie kodu, który nie jest nam potrzebny i usuwania kodu, który nie jest już wykorzystywany.
  • Not Making the Code Easy to Change
  • Najczęściej ten problem, pojawia się przez zbyt wielką liczbę założeń w projekcie, co do tego jak nasz projekt będzie działał w przyszłości, lub przez pisanie kodu bez poświęcenie wystarczająco czasu na projektowanie. Jednym z częstych błędów jest np. przyjęcie założenia, że nasz kod, nie będzie wspierał wielu języków, albo nie wykorzysta frameworka do unit testów. Jeżeli tylko wiemy o konieczności w przyszłości dodania jakiejś zmiany, powinniśmy dodać bardzo minimalny interfejs, który to ułatwi (moim zdaniem troszkę, kłóci się to z pierwszą zasadą).

    "Kod powinien być projektowany, na podstawie wiedzy, którą mamy obecnie, nie na podstawie tego co myślimy, że będzie działo się w przyszłości"
  • Being Too Generic
  • Czyli over-engineering, coś co się przydarza często doświadczonym deweloperom. Próba tworzenia generycznych rozwiązań, które niekoniecznie są potrzebne już w tej chwili, gdy mniej generyczne rozwiązani są szybsze do implementacji i szybciej przynoszą wartość klientowi.

    "Bądź tak generyczny, jak tego potrzebujesz w tej chwili"
  • Incremental Development & Design
  • Za każdym razem, gdy chcesz dodać coś nowego do systemu, rezultat ma być taki jakby zostało to już na początku zaprojektowane do takiego działania. Wymaga to dużo refactoringu. Przystępując do pracy nad projektem najważniejszą kwestią jest to by tworzyć wszystko we właściwej kolejności, zacząć od najbardziej istotnych elementów systemu np. funkcja odtwarzania wideo, przed listą wyboru plików do odtworzenia.