Google Test C++の使い方(初級)
やりたいこと
C++のテストがしたい。
Google Testがいい感じという噂。
教科書
入門まとめ
基本的なアサーション
ASSERT_TRUE(condition); EXPECT_TRUE(condition); condition が true
ASSERT_FALSE(condition); EXPECT_FALSE(condition); condition が false
ASSERT_EQ(x.size(), y.size()) << "Vectors x and y are of unequal length"; for (int i = 0; i < x.size(); ++i) { EXPECT_EQ(x[i], y[i]) << "Vectors x and y differ at index " << i; }
簡単なテスト
プロダクトコード
int Factorial(int n); // nの階乗を返す
テストコード
// 0 の階乗をテスト TEST(FactorialTest, HandlesZeroInput) { EXPECT_EQ(1, Factorial(0)); } // 正の数の階乗をテスト TEST(FactorialTest, HandlesPositiveInput) { EXPECT_EQ(1, Factorial(1)); EXPECT_EQ(2, Factorial(2)); EXPECT_EQ(6, Factorial(3)); EXPECT_EQ(40320, Factorial(8)); }
テストフィクスチャ:複数のテストで同じデータ設定を使う
プロダクトコード
template <typename E> // E は要素の型 class Queue { public: Queue(); void Enqueue(const E& element); E* Dequeue(); // queue が空の場合は NULL を返します. size_t size() const; ... };
テストのフィクスチャ
class QueueTest : public ::testing::Test { protected: virtual void SetUp() { q1_.Enqueue(1); q2_.Enqueue(2); q2_.Enqueue(3); } // virtual void TearDown() {} Queue<int> q0_; Queue<int> q1_; Queue<int> q2_; };
このフィクスチャとTEST_F() を利用したテストコード
TEST_F(QueueTest, IsEmptyInitially) { EXPECT_EQ(0, q0_.size()); } TEST_F(QueueTest, DequeueWorks) { int* n = q0_.Dequeue(); EXPECT_EQ(NULL, n); n = q1_.Dequeue(); ASSERT_TRUE(n != NULL); EXPECT_EQ(1, *n); EXPECT_EQ(0, q1_.size()); delete n; n = q2_.Dequeue(); ASSERT_TRUE(n != NULL); EXPECT_EQ(2, *n); EXPECT_EQ(1, q2_.size()); delete n; }
テストの呼び出し
テストを定義したら,RUN_ALL_TESTS() でテストを実行できる
#include "this/package/foo.h" #include "gtest/gtest.h" namespace { // テスト対象となるクラス Foo のためのフィクスチャ class FooTest : public ::testing::Test { protected: // 以降の関数で中身のないものは自由に削除できます. // FooTest() { // テスト毎に実行される set-up をここに書きます. } virtual ~FooTest() { // テスト毎に実行される,例外を投げない clean-up をここに書きます. } // コンストラクタとデストラクタでは不十分な場合. // 以下のメソッドを定義することができます: virtual void SetUp() { // このコードは,コンストラクタの直後(各テストの直前) // に呼び出されます. } virtual void TearDown() { // このコードは,各テストの直後(デストラクタの直前) // に呼び出されます. } // ここで宣言されるオブジェクトは,テストケース内の全てのテストで利用できます. }; // Abc を行う Foo::Bar() メソッドをテストします. TEST_F(FooTest, MethodBarDoesAbc) { const string input_filepath = "this/package/testdata/myinputfile.dat"; const string output_filepath = "this/package/testdata/myoutputfile.dat"; Foo f; EXPECT_EQ(0, f.Bar(input_filepath, output_filepath)); } // Xyz を行う Foo をテストします. TEST_F(FooTest, DoesXyz) { // Foo の Xyz を検査 } } // namespace int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }
Mockまとめ
わからないことがあったとき
基本ステップ
簡単なマクロを使ってモック化したいインタフェースを記述します.これが,モッククラスの実装に展開されます.
モックオブジェクトを作成し,直感的な構文を利用して Expectation と 動作を規定します.
モックオブジェクトを利用するコードを実行します.Google Mock は,Expectation 違反が起こると即座にそれをキャッチします.
使うための準備
C++ ソースファイル内で, “gtest/gtest.h” と “gmock/gmock.h” を #include するだけで準備は終わり。
モック理解のためのサンプル
class Turtle { ... virtual ~Turtle() {} virtual void PenUp() = 0; virtual void PenDown() = 0; virtual void Forward(int distance) = 0; virtual void Turn(int degrees) = 0; virtual void GoTo(int x, int y) = 0; virtual int GetX() const = 0; virtual int GetY() const = 0; };
モックの定義
Turtle から MockTurtle クラスを派生させます.
Trutle の仮想関数を調べて,引数の数を数えます.
派生クラスの public セクションに,MOCK_METHODn();(const メソッドをモック化する場合は, MOCK_CONST_METHODn();)を書きます.ここで n は,引数の数を表しますが,これを数え間違えると,コンパイルエラーで注意されます. 関数のシグネチャを調べて,その関数名をマクロの1番目の引数に,残りを2番目の引数にします.
これを,モック化したい仮想関数全てに対して繰り返します.
MOCK_METHOD0 のように最後の数字は引数の数を指定。
#include "gmock/gmock.h" // Google Mock はこのヘッダに. class MockTurtle : public Turtle { public: ... MOCK_METHOD0(PenUp, void()); MOCK_METHOD0(PenDown, void()); MOCK_METHOD1(Forward, void(int distance)); MOCK_METHOD1(Turn, void(int degrees)); MOCK_METHOD2(GoTo, void(int x, int y)); MOCK_CONST_METHOD0(GetX, int()); MOCK_CONST_METHOD0(GetY, int()); };
モックの使い方
モックオブジェクトを作成します.
その Expectation を設定します
モックを利用したコードを実行します.Google Test のアサーションを利用して結果のチェックを行っても良いでしょう.モックメソッドが期待よりも多く呼び出される,または引数が誤っている,などの場合は,即座にエラーが起こります.
モックがデストラクトされると,その全ての Expectation が満足されたかどうかを Google Mock が自動的に検証します.
#include "path/to/mock-turtle.h" #include "gmock/gmock.h" #include "gtest/gtest.h" using ::testing::AtLeast; // #1 TEST(PainterTest, CanDrawSomething) { MockTurtle turtle; // #2 EXPECT_CALL(turtle, PenDown()) // #3 .Times(AtLeast(1)); Painter painter(&turtle); // #4 EXPECT_TRUE(painter.DrawCircle(0, 0, 10)); } // #5 int main(int argc, char** argv) { // 以下の行は,テスト開始前に Google Mock (と Google Test) // を初期化するために必ず実行する必要があります. ::testing::InitGoogleMock(&argc, argv); return RUN_ALL_TESTS(); }
Exceptionの作り方
Expectation を設定するために EXPECT_CALL() マクロを使う。
このマクロには2つの引数があり、1番目はモックオブジェクトで,2番目はメソッドと引数。
using ::testing::Return;... EXPECT_CALL(turtle, GetX()) .Times(5) .WillOnce(Return(100)) .WillOnce(Return(150)) .WillRepeatedly(Return(200));
turtle オブジェクトの GetX() メソッドが5回呼ばれ,最初は 100 を返し,次に 150,それ以降は 200 を返す,という動作のテスト。
所感
unittestに似てる。書きながら使えるようになろう~
RPLIDAR A1をROSで動かしてみる
やりたいこと
低価格Lidar RPLIDAR A1を授かったので、ROSで動かしてみる
教科書
実行手順
びっくりするくらいシンプル。素晴らしい。
catkin_make
source devel/setup.bash
ポートに権限付与
ls -l /dev | grep ttyUSB
sudo chmod 666 /dev/ttyUSB0
roslaunch rplidar_ros view_rplidar.launch
このlaunchを立ち上げると、こんな感じ ↓
ノードだけ立ち上げるときは
- roslaunch rplidar_ros rplidar.launch
出力されているTopicは
- scan (sensor_msgs/LaserScan) : it publishes scan topic from the laser.
How to install rplidar to your robot
rplidar rotate with clockwise direction . The first range come from the front ( the tail with the line).
所感
とてもシンプル!ありがたい!!
次はルンバで自律移動にチャレンジ。どのSLAMの手法を使おう!?
gmappingかKarto SLAMがよさげかな。。。
参考 :
GPD pocketにUbuntu16.04 & ROS install
超小型でなかなかスペックが良い♪
やりたいこと
Windows10が入っているGPDにUbuntu16.04とROSをインストール。
ざっくりまとめ。
Ubuntuインストールのための準備
以下はすべてGPD上で実施
BIOSの変更
2017/06/28版のZipファイルをGPD Pocket/BIOS - GPD Wikiから取得。2017/06/28版でないとUbuntuは動かないらしい。
Zipを解答し、update_win.batをGPD上で管理者権限で実行。詳細は以下を参考。
msinfoでBIOSバージョンが正しくかわっているか確認。
ISOファイルのダウンロード
- 第3版 ubuntu-16.04.1-desktop-amd_0809_2.iso をGPD Pocket/OS/Ubuntu - GPD Wikiから取得
UltraISOのインストール
2017/06/28版のZip内のUbuntu安装说明.pdfをGoogle翻訳のファイルから翻訳を利用して翻訳しておく
ISOイメージの作り方
Ubuntu安装说明.pdfを参考。中国語なので、Google翻訳したものを見るとわかりやすい。
ブート用USBをさす。
UltraISOを開き、ファイルを開くからISOファイルを選択、読み込み。
上部タブのブートを選択し、イメージの書き込みをクリック。
書き込み設定がUSB-HDD+になっていることを確認し、USBに書き込み実行。
Ubuntuのインストール
ブータブルUSBをさして、再起動し、Fn + F7を複数回打ち込む。
のような画面がでてくるので、UEFIを選択。
Try Ubuntu without installingを選択。
Gpartedでパーティションを作成。ルートとswap。
Ubuntu install アイコンを選択。
ドライバを入れる項目はチェック無しで実行。インストールはそれ以外を選択し、上記作成パーティションにインストール。
終了したら再起動!
画面が90度回転している時
Ubuntuのシステム設定のディスプレイで回転させる。
ROSのインストール
以下の手順をコピペで完了!
これでGPD pocketでROS KINETICが動いた〜↓
所感
小さい割にスペックいいし、Ubuntu動くし、これからいろいろ試したい! 小さいロボットにもギリ載せれそう。
中国語の資料つらかった。。。
Linux(Ubuntu16.04)でのプリンタの設定方法&コマンドラインでの印刷の仕方
実験用のために小型フォトプリンタCP710を1000円で購入。安かった。
このシリーズは外付けバッテリで動くのが個人的には魅力的。
外付けバッテリ: Amazon CAPTCHA
やりたいこと
Linux PCでプリンタを使いたい。
コマンドラインで任意のタイミングで印刷したい!
参考HP
ドライバの入手先
公式HPをチェック。なければ↓
Gutenprint Printer Driversをチェック。なければ↓
openprintingでドライバインストール
上記から 5.2.7 (DEB for LSB 3.2) を選択し、ダンロード
openprinting:database:driverpackages [Linux Foundation Wiki]
に従って
sudo apt-get install lsb
$ dpkg -i "name of the .deb package"
でインストール完了
設定前のインストール
sudo apt-get install cups
sudo apt-get install smbclient
プリンタの追加・設定
CUPSでの設定
が参考になりました。ありがとうございます!
CUPSで印刷トライ
CUPSを使ったUbuntu16.04LTSでのプリンタの設定
上記に従って登録後、下記写真のMaintenance -> Test Print Pageを選択
で印刷完了 ↓
設定の確認
Test Printできたプリンタ設定がデフォルトのプリンタ設定になっているか(左上のチェックがついてるか)を確認。
なっていない場合は右クリック->デフォルトに設定で変更。
コマンドラインで印刷
【Linux入門】しっかりわかる!プリンタ管理と印刷コマンドがわかりやすい。感謝です。
ここまでできていると、印刷したい写真ファイル名がtest.pngだとすると、以下lpコマンドで
$ sudo lp test.png
印刷ができる〜!
参考:
所感
はじめてLinuxでプリンタの設定や印刷をしてみた。コマンドラインで印刷できたし、いろいろな用途に使えそう♪
おまけ
以下のシステム設定で素直に設定した場合だと、プリンタがすぐ「一時停止」状態になり、印刷出来なかった。
システム設定
システム設定 -> プリンタ で以下のような画面になっていたらCP710が正しく認識されている。
エラー時の対処
もし、追加時に"client-error-not-possible"がでたら...
- sudo cp gutenprint52+usb gutenprint52usb
参考: 14.04 - Installing CP400 printer gives 'client-error-not-possible' error - Ask Ubuntu
Raspberry Pi Zero W で遊んでみる(3)~アクセスポイント化~
やりたいこと
WIFI環境がない場所でもひとつのraspi zero wをアクセスポイントとして通信がしたい
なので、raspi zero w をアクセスポイント化にトライ
教科書
MACアドレスを調べる
pi@raspberrypi:~$ iw dev
udev ruleを追加
ファイルを作成
$ sudo nano /etc/udev/rules.d/70-persistent-net.rules
以下の"b8:27:eb:ff:ff:ff"の部分を先に調べたMACアドレスに書き換えて上のファイルに記述
SUBSYSTEM=="ieee80211", ACTION=="add|change", ATTR{macaddress}=="b8:27:eb:ff:ff:ff", KERNEL=="phy0", \ RUN+="/sbin/iw phy phy0 interface add ap0 type __ap", \ RUN+="/bin/ip link set ap0 address b8:27:eb:ff:ff:ff"
Dnsmasq and Hostapdのインストール
$ sudo apt-get install dnsmasq hostapd
Dnsmasq and Hostapdのためのファイル設定
3つのファイルを書き換える
1. /etc/dnsmasq.conf
interface=lo,ap0 no-dhcp-interface=lo,wlan0 bind-interfaces server=8.8.8.8 domain-needed bogus-priv dhcp-range=192.168.10.50,192.168.10.150,12h
2. /etc/hostapd/hostapd.conf
以下のssidとpassphraseを自分の好きな名前に設定する。" "で囲む必要はない。
ctrl_interface=/var/run/hostapd ctrl_interface_group=0 interface=ap0 driver=nl80211 ssid=YourApNameHere hw_mode=g channel=11 wmm_enabled=0 macaddr_acl=0 auth_algs=1 wpa=2 wpa_passphrase=YourPassPhraseHere wpa_key_mgmt=WPA-PSK wpa_pairwise=TKIP CCMP rsn_pairwise=CCMP
3. /etc/default/hostapd
DAEMON_CONF="/etc/hostapd/hostapd.conf"
Interfaces Fileの修正
1. /etc/wpa_supplicant/wpa_supplicant.conf
使用できるWIFIがあればそのWIFIのSSIDとパスワードを設定
country=JP ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev update_config=1 network={ ssid="YourSSID1" psk="YourPassphrase1" id_str="AP1" }
2. /etc/network/interfaces
# interfaces(5) file used by ifup(8) and ifdown(8) # Please note that this file is written to be used with dhcpcd # For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf' # Include files from /etc/network/interfaces.d: source-directory /etc/network/interfaces.d auto lo auto ap0 auto wlan0 iface lo inet loopback allow-hotplug ap0 iface ap0 inet static address 192.168.10.1 netmask 255.255.255.0 hostapd /etc/hostapd/hostapd.conf allow-hotplug wlan0 iface wlan0 inet manual wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf iface AP1 inet dhcp
起動時の設定
/home/piに以下シェルスクリプトを作成
pi@raspberrypi:~$ cat ./start-ap-managed-wifi.sh #!/bin/bash sleep 30 sudo ifdown --force wlan0 && sudo ifdown --force ap0 && sudo ifup ap0 && sudo ifup wlan0 sudo sysctl -w net.ipv4.ip_forward=1 sudo iptables -t nat -A POSTROUTING -s 192.168.10.0/24 ! -d 192.168.10.0/24 -j MASQUERADE sudo systemctl restart dnsmasq
実行権限を付加
pi@raspberrypi:~$ chmod +x ./start-ap-managed-wifi.sh
起動時に実行するために、cronに設定
$ sudo crontab -e
以下を最終行に追加
@reboot /home/pi/start-ap-managed-wifi.sh
最後に...
リブート!
これで母艦PCのwifiを見ると設定したSSIDが見えるはず!!
コメント
おまけ
sshのホスト名を変更する方法
$ sudo -e /etc/hostname 変更する $ reboot
再起動するとssh -X pi@変更後のホスト名.localで接続可能
udevについて
有線LANを接続する方法
USB OTG
名前解決
参考
Raspberry Pi Zero W で遊んでみる(0)~インストール・設定~
やりたいこと
raspberry pi zero w のインストールや設定方法をまとめる
使っているバッテリーはこれ👇でとても小さい
ポータブル充電器02 通販 | au オンラインショップ | スマホ・携帯電話向けオプション品
もっと小さいバッテリーを知ってる方いたら教えてください> <
pin配置
OSダウンロード
OSの書き込み
Etcher <- 簡単おすすめ
- うまく行かない時はカードリーダを交換してみよう
Ubuntuで、RaspberryPiのOSをSDカードに書き込む | Hornet|静岡拠点のWeb、ホームページ制作
設定教科書
wifi設定
SDカード内のbootディレクトリを探し、以下のファイルをboot直下に作成
- emacs -nw /Volumes/boot/wpa_supplicant.conf
country=JP ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev update_config=1 network={ ssid="your-SSID" psk="your-passphrase" }
このSDを挿すとWIFIに接続される
USB経由でインターネット接続したいとき
参考: Raspberry Pi Zero(W)のセットアップ
bootドライブ内のcmdline.txtに "modules-load=dwc2,g_ether" を追加します。
rootwaitとquietの間です。エディタはvimを使っていますが、適宜変えてください。
次に、config.txtの末尾に"dtoverlay=dwc2"を追加します。
$ echo "dtoverlay=dwc2" >> /Volumes/boot/config.txt
例
dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait modules-load=dwc2,g_ether quiet init=/usr/lib/raspi-config/init_resize.sh quiet splash plymouth.ignore-serial-consoles
SSH対応
設定
touch /Volumes/boot/ssh
ログイン
ssh -X pi@raspberrypi.local
初期ユーザーはpi、初期パスワードはraspberryになります。
wifi安定化
参考:
rfkillフラグのリセット問題が発動すると面倒なので、念のため。
$ sudo apt install rfkill
$ sudo vi /etc/rc.local
下記を追加。
#By default this script does nothing.
/usr/sbin/rfkill unblock wifi
初期設定
$ sudo apt-get update $ sudo apt-get upgrade $ sudo apt-get install tmux emacs $ sudo raspi-config
スペースキーで選択
"4. Localization Options"から"11. Change Locale"を選択して、"ja_JP.UTF-8"を有効に。
同様に"4. Localization Options"から"12 Change Timezone"。"Asia"、"Tokyo"と順にたどっていく。
参考
Raspberry Pi Zero W で遊んでみる(2)~ROS KINETIC INSTALL~
やりたいこと
ラズパイゼロにROSを入れる
教科書
ROSではじめるホビーロボット#06がほしい。手に入る方法ないのかな。。。
インストール
$ sudo apt-get update $ sudo apt-get install -y build-essential gdebi python-defusedxml libboost-all-dev liblog4cxx-dev libconsole-bridge-dev $ sudo pip install netifaces $ mkdir -p ~/tmp $ cd ~/tmp $ wget https://github.com/nomumu/Kinetic4RPiZero/releases/download/v_2017-10-15/rpi-zerow-kinetic_1.0.0-1_armhf.zip $ unzip rpi-zerow-kinetic_1.0.0-1_armhf.zip $ sudo gdebi rpi-zerow-kinetic_1.0.0-1_armhf.deb $ sudo /opt/ros/kinetic/initialize.sh
設定
$ sudo rosdep init $ rosdep update $ echo "source /opt/ros/kinetic/setup.bash" >> ~/.bashrc $ source ~/.bashrc
roscore
動いた〜!
コメント
のむむさんありがとうございますm( )m