cunit单元测试

以md5测试为例子,练习了cunit这个单元测试工具。 要写一个测试用例,只需要遵循用例的框架编写就好了。 我们应该要清楚自己编写的函数的输入是什么,输出是什么。然后使用cunit的断言看结果是否符合预期,是的话测试通过,否则说明编码有问题。 就这次将要编写的md5为例,需要测试两个函数,一个是输入字符串,输出计算后的md5值,另一个是输入文件路径,输出文件的md5值。所以用例是否通过的条件就是计算的md5值是否正确。 先来看看main函数 :::c int main(int argc, const char *argv[]) { return run_test(); } 没什么特别的,就是运行了run_test这个函数。 再来看看run_test :::c int run_test() { if(CU_initialize_registry()) { exit(EXIT_FAILURE); } else { AddTests(); /**** Automated Mode ***************** CU_set_output_filename("TestMax"); CU_list_tests_to_file(); CU_automated_run_tests(); //************************************/ /*********basic mode**************/ // CU_basic_set_mode(CU_BRM_VERBOSE); // CU_basic_run_tests(); /*********console mode**************/ CU_console_run_tests(); CU_cleanup_registry(); return CU_get_error(); } } 开始变得有趣了,我们看到运行cunit,先要执行CU_initialize_registry(),成功后运行我们写的AddTests添加测试用例,接着运行测试模式,这里有三种,我用了第三种控制台模式。最后return退出。 接着来看看我们的AddTests做了什么工作。 :::c void AddTests() { assert(NULL != CU_get_registry()); assert(!CU_is_test_running()); if(CUE_SUCCESS != CU_register_suites(suites)) { exit(EXIT_FAILURE); } } 原来AddTests的动作就是注册suites。那么什么是suites? :::c CU_TestInfo testcase[] = { {"test for md5", test_md5_null}, {"test for md5 a", test_md5_a}, {"test for md5 letter", test_md5_letter}, CU_TEST_INFO_NULL }; CU_TestInfo testcase2[] = { {"test for md5 file", test_md5_file}, CU_TEST_INFO_NULL }; int suite_success_init(void) { return 0; } int suite_success_clean(void) { return 0; } CU_SuiteInfo suites[] = { {"test suite 1", suite_success_init, suite_success_clean,testcase}, {"test suite 2", suite_success_init, suite_success_clean,testcase2}, CU_SUITE_INFO_NULL }; 从下往上看,suites 其实就是记录SuiteInfo的结构体,这里有两个suite,分别是suite1和suite2,而suite1中包含三个测试用例,suite2中包含一个。...

July 25, 2013

GIT速查表与实践

pdf 下载地址:https://dl.dropboxusercontent.com/u/41178008/Git_Cheat_Sheet__grey.pdf

July 1, 2013

吃素-的世界

素食的经历还停留在小时候,因为那时经常跟着婆婆去各个寺庙。 个人不是一个素食者,却对素食颇有兴趣,尤其是对于那些可以把素装成肉的菜式。 在女朋友的提议下来到广州的佛世界素食社-一家老牌素食馆-体验了一下素菜。 ##第一道菜是这个 忘记名字了。什锦煲之类的,味道刚好。感觉上加点咸鱼就成那啥煲了。 ##第二个菜 各种菌,也是味道不错的,想起某个菌的广告了。你今天吃了吗? ##能填肚子的主食 这是煎面,没错是煎的。里面还有鱼丸片,没错是鱼丸片,素的吧,分不清了,世界观被颠覆了。

June 27, 2013

嵌入式开发板配置无线上网总结

手头有一块tiny210,但是没有网线,不能有线上网,只能为其设置无线网卡上网了。 配置上网的环境有这些 开发板用的debain根文件系统和kernel linux 3.0.8 wifi网卡,芯片型号是RTL8188CUS 串口(主要交互工具了) 首先是要去下载无线网卡的驱动和相关工具:点这里,找到RTL8188CUS,这一项的Unix(Linux),下载文件,看介绍支持Linux Kernel 2.6.18~2.6.38 和 Kernel 3.0.8 得到RTL8192xC_USB_linux_v3.4.4_4749.20121105.zip这个文件,使用unzip解压它。 进去后发现东西很齐全。主要使用的文件夹有三个driver wireless_tools和wpa_supplicant_hostapd ##driver 进去后又是一个压缩包,如果使用的是友善提供的内核源码,里面已经包含了这款芯片的驱动了,无需再折腾,否则的话,就需要这个文件夹里面的文件了。此处先占个坑。 ##编译wireless_tools 编译wireless 比较简单,修改makefile的相关变量就可以了。 :::sh #由于这些工具需要安装到debain文件系统中,所以需要配置PREFIX,让Makefile知道编译好的文件放在哪里 ifndef PREFIX PREFIX = /home/gavin/workspace/min210/debain_rootfs endif ## Compiler to use (modify this for cross compile). #如果配置了PATH,使用友善提供的交叉工具链,才可以这样写。 CC = arm-none-linux-gnueabi-gcc ## Other tools you need to modify for cross compile (static lib only). AR = arm-none-linux-gnueabi-ar RANLIB = arm-none-linux-gnueabi-ranlib 简单的make && make install就可以了,执行完后发现文件系统多了下面一些文件 :::sh include/ lib/libiw.a man/ sbin/ifrename sbin/iwconfig sbin/iwevent sbin/iwgetid sbin/iwlist sbin/iwpriv sbin/iwspy 这些都是无线网卡有用的工具,后面会用到。...

June 27, 2013

android系统预安装可卸载应用程序

##基本思路 要编译预置程序的android系统,网上的方法是把程序放到/system/app目录中,但是这样做的话,程序不可卸载,而且如果不同程序的动态链接库名字相同的话,这两个应用程序就不能同时安装。 这里使用的方法是把程序放在/data/app目录,这样程序既可卸载,也可升级,更可共存,重新开机程序不会还原,恢复出厂设置后自动安装程序,一举n得。 流程是这样的:开机运行脚本检测/data/app目录是否有preinstall.txt这个文件,没有的话表示预置的程序没有安装,这时就从指定目录/system/media/app里把预置的apk复制到/data/app目录。 ##实现 首先是实现那个脚本。我把它起名为init.gavin.preinstall.sh :::sh #init.gavin.preinstall.sh #system/core/rootdir/etc/ #!/system/bin/sh cd /system/media/app #android shell script: check if preinstall.txt is exist if [ -s /data/app/preinstall.txt ]; then echo "don't need to copy preinstall files" else # scan all apk files under system/media/app apklist="$(ls)" for apkfile in ${apklist}; do #copy all apk file to data/app dd if=${apkfile} of=/data/app/${apkfile} # change the permission chmod 666 /data/app/${apkfile} done fi 问题来了,这个文件放在系统哪里?放到/etc/目录。 问题又来了,编译的时候怎么自动把他放到根文件系统的/etc/目录?在system/core/rootdir/Android.mk文件中加入下面的代码 :::sh #system/core/rootdir/Android.mk include $(CLEAR_VARS) LOCAL_MODULE := init....

June 19, 2013

shell使用笔记

变量赋值 :::java #输入的第一个参数赋值给INTENT INTENT = $1 无输入和输出的函数 :::java function xxx() { } #调用的话 xxx 条件判断 :::java if [ "$TARGET_PRODUCT" = "rk30sdk" ]; then if [ -z "$INTENT" ]; then help else ....... fi else echo "please lunch to chose a rockchip product" fi sed使用 :::java #这里使用了嵌套,先找到该行,再把true替换成false sed -i '/BUILD_WITH_SUPERUSER/{s/true/false/g}' $ANDROID_BUILD_TOP/device/rockchip/$TARGET_PRODUCT/BoardConfig.mk case的使用 :::java case $1 in "user" ) prepare_user ;; "develop" ) prepare_develop ;; * ) echo "input error" ;; esac

June 18, 2013

算法第二课笔记

大O符号 $f(n)=O(g(n))$ 的意思是存在常数 $c>0$ 和 $n>{n}_{o}$ ,使得 $$0 \leq f(n) \leq cg(n)$$ 其中 $n\geq{n}_{o}$ 例子 $2{n}^{2}=O({n}^{3})$ 其实在这些符号的等号不是相等的意思,而是是的意思。在这个例子中,$O({n}^{3})$ 是$2{n}^{2}$的上界,这是显而易见的。 $\Omega$符号 有上界就会有下界,定义与O差不多,只是符号反了过来 例子 $$\sqrt{n}=\Omega(lgn)$$ $\Theta$符号 定义为$O$与$\Omega$的交集。 $$ \Theta(g(n))=O(g(n))\bigcap\Omega(g(n)) $$ 解递归 解递归没有特定的方法,这里有三种解递归的方法。 方法一:递推法 递推法常用来检验解递归公式的正确性,因为其第一步的动作是要猜测递归的解大概是什么。下面是基本流程 猜测结果是什么 用归纳法验证 求出常数项 例子 $$T(n)=4T(n/2)+n$$ 我们知道 $T(1)=\Theta(1)$。 先猜测$T(n)=O({n}^{3})$ 归纳法验证 假设对于所有$k<n$,$T(k) \leq c{k}^{3}$,那么 $$ T(n)=4T(n/2)+n=4c {(\frac{kn}{2})}^{3} +n= \frac{1}{2} c{n}^{3}+n $$ $$ = c{n}^{3}- \frac{1}{2}c({n}^{3}-n) \leq c{n}^{3}如果 \frac{1}{2}c{n}^{3}-n \geq 0 $$ $$ e.g c \geq 1 n \geq 1 $$ 方法二:递归书 递归书很好用,但是不严谨,有猜测的成分。基本思想就是画递归树,然后把每次递归的时间加起来,就是总时间了。...

June 5, 2013

第七章:加速

##习惯使用hjkl 抛弃方向键吧,事实证明,在vim中,使用hjkl移动更加高效,因为手不需要跑去摸方向键,一切操作都在某个范围内即可完成。 在普通模式,hjkl的定义是这样的 h 左 j 下 k 上 l 右 ##区分实际行与显示行 有时候,由于vim窗口的大小限制,一行的数据可能会被截断成两行显示,而我们在进行移动时,默认是按真实的行数来移动的,但是有时候只是想移动同一真实行的后半部分,我们可以使用gj和gk来进行移动。还有一些其他的快捷键,如下: 键值 作用 j 真实行下移 gj 显示行下移 k 真实行上移 gk 显示行上移 0 跳到真实行的第一个字符 g0 跳到显示行的第一个字符 ^ 跳到真实行第一个非空字符 g^ 跳到显示行第一个非空字符 $ 跳到真实行的最后一个字符 g$ 跳到显示行最后一个字符 如果想j来跳转显示行,可以这样配置 :::sh nnoremap k gk nnoremap gk k nnoremap j gj nnoremap gj j ##在单词间跳转 直接给出相关命令。 命令 作用 w 跳到下一单词的开头 b 跳到当前或之前单词的开头 e 跳到当前或下一单词的结尾 ge 跳到前一单词的结尾处 ##查找字母 如果在一行里直接跳到某个字母我们可以使用f{char},然后想跳到下一个,就可以使用;重复动作了。

May 30, 2013

算法-又一坑

对于一个软件工程师,算法重要吗?如果想混日子,应该不重要。 但是想进步,这个基础却必须打好。 君不见国外的工程师面试,数据结构和算法可是大头。 我们经常使用各种API,却不知道个中原理。即使看源码,还是容易云里雾里的。 算法,无论如何也要攻克。 所以,开个坑,学算法去。 ##传说 有一个关于高斯同学的故事,与算法有关,故事是这样的: 高斯上小学的时候,老师出了一个问题,做完就可以放学,这个问题很简单: 1+2+3+4+5+6……+100=? 结果,高斯很早就放学了。因为他会高效的算法,当其他同学一个一个算的时候,他却是这样算的。 :::java 1 +2 +3 +4 +5.....+97+98+99+100 + 100+99+98+97+95....+4 +3 +2 +1 = 101+101+101+101+101….+101+101+101+101= 101*100=10100 1 +2 +3 +4 +5…..+97+98+99+100 = 10100/2 = 5050 高斯真是个聪明的孩子,别人用的时间是O(n),他用的是O(1)。当然快了。 ##一个例子 编程的思想,除了"KISS",还需要高效,虽然现在的计算机和手持设备都足够强大了,但是还没有到为所欲为的地步,没有高效的算法,软件寸步难行。 有一个例子,计算斐波那契数,这是C语言程序设计一开始就介绍的。 :::c double fib1(int n) { if(n <= 0) return -1; if(n == 1) return 0; if(n == 2) return 1; return fib1(n - 1) + fib1(n - 2); } 算法很简单,教科书答案,但是用了递归,效率像掉进了万象深渊。为什么这么说,可以用一张图来解释。 其时间复杂度为$T(n) = \frac{1}{\sqrt{5}} ({( \frac{1 + \sqrt{5}}{2})}^{n} - {( \frac{ 1 - \sqrt{5}}{2} )}^{n})$...

May 29, 2013

githug通关攻略

这货叫做githug,而不是大家熟悉的github,其主要目的是通过游戏的形式来让我们练习git的使用。 ##安装githug githug是ruby写的一个应用。所以先要安装ruby,然后输入 :::sh gem install githug 然后就可以在你觉得合适的目录输入githug :::sh ******************************************************************************** * Githug * ******************************************************************************** No githug directory found, do you wish to create one? [yn] y 强烈建议把git的编辑器转换为vim :::sh git config --global core.editor "/usr/local/bin/vim" ##Level 1 :::sh Level: 1 Difficulty: * A new directory, git_hug, has been created; initialize an empty repository in it 开始总是简单的,这题是如何新建一个仓库 :::sh cd git_hug git init githug ##Level 2 :::sh Level: 2 Difficulty: * There is a file in your folder called README, you should add it to your staging area Note: You start each level with a new repo....

May 3, 2013