Live Hacking Before (Formal) Unit Testing

Initial Structure

$ tree
.
├── bin
│   └── CMakeLists.txt
├── CMakeLists.txt
├── src
│   └── userdb
│       └── CMakeLists.txt
└── tests
    └── CMakeLists.txt

Talk about project plan

  • In memory UserDB. Features

    • Load/store from/to file

    • Search

    • Iterate

User

Talk

  • Database payload

  • ID is going to be primary key

  • UserDB

UserDB

  • Create file from scratch (it is the class that we will be talking about)

void insert(const User& u) { /*not caring about duplicates*/ }

bin/userdb-write-binaryfile.cpp

Talk

  • End goal: dump db into file format

  • Start with program bin/userdb-write-binaryfile.cpp

    Pull in write-initial

  • Think about writing

    • Commandline parameter ⟶ filename

    • How?

    • db.write(filename);

Extend UserDB To Write

In bin/userdb-write-binaryfile.cpp

  • Add argv[1] ⟶ filename

  • Add call db.write(filename)

In src/userdb/userdb.{h,cpp}, implement UserDB::write(const string&)

  • Write a chapter of method documentation!

  • Loop over std::map entries (using range based for)

  • Pull in binary-user

  • open(... O_CREAT|O_TRUNC|O_WRONLY, 0666) (assert’ing that all is well)

    Mode 0666!!

  • Convert User to BinaryUser

    • Use htons() from <arpa/inet.h>

    • write(), again only assert’ing

  • Look into written file, using od -c

  • Complete bin/userdb-write-binaryfile.cpp, to not write hardwired users

    • Pull in user-from-stdin

  • Finally, use bin/userdb-write-binaryfile to enter

Extend UserDB To Read From File, And Iterate

  • Pull in read-and-dump into bin/userdb-read-binaryfile.cpp

  • Add to CMakeLists.txt

  • Implement UserDB::read()

    • Pull in read-binary into body of read()

  • Compile, and see the iteration still not implemented

  • Pull userdb-iterator into userdb.h

  • Pull begin-end into userdb.h

Bug: Use “Faschingbauer” As Last Name

  • Create a new database,

  • Dump it. See that email got overwritten.

  • Write tests/test-funny-overflow.cpp. Suspecting the inmem DB to loose things (foolishly).

    • Pull in test-funny-overflow into empty file

    • Add to CMakeLists.txt

    • Build

    • Implement UserDB::find()

    • Run

    • Works ⟶ next test

  • Write tests/test-funny-overflow-file.cpp

    • Copy tests/test-funny-overflow.cpp to tests/test-funny-overflow-file.cpp

    • Pull in temp-file, right inside main()

    • Find bug

  • Discuss: either change everything (errorhandling!)

    • ⟶ no, lets just silently truncate

    • ⟶ document that as a feature (i.e. modify the test to require “Faschingb”)

Wrap Up: What Do We Have?

  • Code base that works, somehow

  • How do we know?

  • ⟶ we have two tests

$ for test in ./test-*; do [ -x $test ] && ( $test && echo "SUCCESS: $test" 1>&2 || echo "FAILURE: $test" 1>&2 ) done
SUCCESS: ./test-funny-overflow
SUCCESS: ./test-funny-overflow-file
  • test-funny-overflow is actually testing UserDB::find()

  • Rename to test-find