├── README.md ├── SWEN90006_Tutorial_1.ipynb ├── SWEN90006_Tutorial_10.ipynb ├── SWEN90006_Tutorial_2.ipynb ├── SWEN90006_Tutorial_3.ipynb ├── SWEN90006_Tutorial_3_2024.ipynb ├── SWEN90006_Tutorial_4.ipynb ├── SWEN90006_Tutorial_4_2024.ipynb ├── SWEN90006_Tutorial_5.ipynb ├── SWEN90006_Tutorial_6.ipynb ├── SWEN90006_Tutorial_7.ipynb ├── SWEN90006_Tutorial_8.ipynb ├── SWEN90006_Tutorial_8_2024.ipynb ├── SWEN90006_Tutorial_9.ipynb ├── SWEN90006_Tutorial_9_2024.ipynb └── figures ├── CFG-Tutorial-3.png ├── CFG-Tutorial-4.png ├── CFG-Tutorial-5.png ├── CFG1_tut4.png ├── Graph-State-Diagram.png ├── Input_structure_tut8.png ├── LWIG-TTT.png ├── Log-Graph.png └── min-execution-tree.png /README.md: -------------------------------------------------------------------------------- 1 | # tutorials -------------------------------------------------------------------------------- /SWEN90006_Tutorial_1.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "colab_type": "text", 7 | "id": "view-in-github" 8 | }, 9 | "source": [ 10 | "\"Open" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": { 16 | "id": "4Yoio5FLmgc4" 17 | }, 18 | "source": [ 19 | "# SWEN90006 Tutorial 1\n" 20 | ] 21 | }, 22 | { 23 | "cell_type": "markdown", 24 | "metadata": { 25 | "id": "q8v6WXHiuzj2" 26 | }, 27 | "source": [ 28 | "## What is testing really?\n", 29 | "\n", 30 | "> *It works! Trust me, I've tested the code thoroughly!*\n", 31 | "\n", 32 | "With those bold words many software projects have been made bankrupt.\n", 33 | "\n", 34 | "The aim of this tutorial is to start to get an understanding of our\n", 35 | "major themes; that is, of the factors that make up quality and how\n", 36 | "testing effects them.\n", 37 | "\n", 38 | "Because we have not looked at testing formally yet, in this tutorial, you will be asked to test a small program fragment. It is a teaser to see where the difficulties of testing lay in practice." 39 | ] 40 | }, 41 | { 42 | "cell_type": "markdown", 43 | "metadata": { 44 | "id": "OKIqiwmCu13k" 45 | }, 46 | "source": [ 47 | "## Important terminology\n", 48 | "\n", 49 | "Before beginning the exercises, consider the following three\n", 50 | "definitions, the first three of which are defined in the chapter [Introduction to software testing](https://swen90006.github.io/notes/An-Introduction-to-Testing.html) of the subject notes:\n", 51 | "\n", 52 | "- *Fault*: An incorrect step, process, or data definition in a computer program. Faults are the source of failures -- fault in the program triggers a failure under the right circumstances.\n", 53 | "\n", 54 | "- *Failure*: A deviation between the observed behaviour of a program, or a system, from its specification. Faults cause failures; and in fact, one fault can cause many failures.\n", 55 | "\n", 56 | "- *Error*: An incorrect *internal* state that is the result of some fault. An error may not result in a failure -- it is possible that an internal state is incorrect but that it does not affect the output. \n", 57 | "\n", 58 | "*Faults cause failures and errors*. A fault in a program can trigger a failure and/or an error under the right circumstances. In fact, a single fault could cause multiple failures and multiple errors. \n", 59 | "\n", 60 | "In normal language, software faults are usually referred to as \"bugs\", but the term \"bug\" is ambiguous and can mean to faults, failures, or errors; as such, as will avoid this term." 61 | ] 62 | }, 63 | { 64 | "cell_type": "markdown", 65 | "metadata": { 66 | "id": "yAwh3-G8oG7U" 67 | }, 68 | "source": [ 69 | "## Your tasks\n", 70 | "\n", 71 | "The small programs below are taken from the exercises in Chapter 1 of *Introduction to Software Testing* by Offutt and Ammann. For each program, the test case below the program results in a failure that is caused by a fault in the program.\n", 72 | "\n", 73 | "For each of the programs below, perform the following tasks:\n", 74 | "\n", 75 | "1. Identify the required data type of inputs. From next week, we formally refers to this as the Input Domain. \n", 76 | "2. Identify the fault.\n", 77 | "3. If possible, identify a test case that does not execute the faulty statement.\n", 78 | "4. If possible, identify a test case that executes the faulty statement, but does not result in an failure.\n", 79 | "5. If possible, identify a test case that forces the program into an error, but does not produce a failure.\n", 80 | "6. Fix the fault and verify that the given test now produces the expected output.\n", 81 | "7. [Open-ended discussion] Do you think your fix guarantees zero failures? " 82 | ] 83 | }, 84 | { 85 | "cell_type": "markdown", 86 | "metadata": { 87 | "id": "lyQmz4pxoky5" 88 | }, 89 | "source": [ 90 | "## The programs" 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": 1, 96 | "metadata": { 97 | "colab": { 98 | "base_uri": "https://localhost:8080/", 99 | "height": 199 100 | }, 101 | "id": "Pi-i5TeomNRZ", 102 | "outputId": "4d0f9574-fb0f-48cb-d670-8c1266e83451" 103 | }, 104 | "outputs": [ 105 | { 106 | "ename": "AssertionError", 107 | "evalue": "ignored", 108 | "output_type": "error", 109 | "traceback": [ 110 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 111 | "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)", 112 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m3\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0my\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 19\u001b[0;31m \u001b[0;32massert\u001b[0m \u001b[0mfind_last\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"Test failed: find_last(%s, %d) == %d\"\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfind_last\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 113 | "\u001b[0;31mAssertionError\u001b[0m: Test failed: find_last([2, 3, 5], 2) == -1" 114 | ] 115 | } 116 | ], 117 | "source": [ 118 | "'''\n", 119 | " x is a list of integers\n", 120 | " y is an integer\n", 121 | " Return the index of the last element in x that equals y. \n", 122 | " If no such element exists, return -1\n", 123 | "'''\n", 124 | "def find_last (x, y):\n", 125 | " i = len(x) - 1\n", 126 | " while i > 0:\n", 127 | " if x[i] == y:\n", 128 | " return i\n", 129 | " i -= 1\n", 130 | " return -1\n", 131 | "\n", 132 | "# The expected output is 0 (the 0th element)\n", 133 | "x = [2, 3, 5]\n", 134 | "y = 2\n", 135 | "assert find_last(x, y) == 0, \"Test failed: find_last(%s, %d) == %d\" % (x, y, find_last(x, y))" 136 | ] 137 | }, 138 | { 139 | "cell_type": "code", 140 | "execution_count": null, 141 | "metadata": { 142 | "colab": { 143 | "base_uri": "https://localhost:8080/", 144 | "height": 197 145 | }, 146 | "id": "IWbgJIK0qr9d", 147 | "outputId": "10a8edd4-f22a-437d-bec6-8afb9ef15400" 148 | }, 149 | "outputs": [ 150 | { 151 | "ename": "AssertionError", 152 | "evalue": "ignored", 153 | "output_type": "error", 154 | "traceback": [ 155 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 156 | "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)", 157 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0;31m# The expected output is 2\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 17\u001b[0;31m \u001b[0;32massert\u001b[0m \u001b[0mlast_zero\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"Test failed: last_zero(%s) == %d\"\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlast_zero\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 158 | "\u001b[0;31mAssertionError\u001b[0m: Test failed: last_zero([0, 1, 0]) == 0" 159 | ] 160 | } 161 | ], 162 | "source": [ 163 | "'''\n", 164 | " x is a list of integers\n", 165 | " Return the index of the LAST 0 in x.\n", 166 | " Return -1 if 0 does not occur in x.\n", 167 | "'''\n", 168 | "def last_zero(x):\n", 169 | " i = 0\n", 170 | " while i < len(x):\n", 171 | " if x[i] == 0:\n", 172 | " return i\n", 173 | " i += 1\n", 174 | " return -1\n", 175 | "\n", 176 | "# The expected output is 2\n", 177 | "x = [0, 1, 0]\n", 178 | "assert last_zero(x) == 2, \"Test failed: last_zero(%s) == %d\" % (x, last_zero(x))" 179 | ] 180 | }, 181 | { 182 | "cell_type": "code", 183 | "execution_count": null, 184 | "metadata": { 185 | "colab": { 186 | "base_uri": "https://localhost:8080/", 187 | "height": 197 188 | }, 189 | "id": "RdDJeQCNrIVt", 190 | "outputId": "79b8c2b7-75b6-4196-92c5-a5f0700334e1" 191 | }, 192 | "outputs": [ 193 | { 194 | "ename": "AssertionError", 195 | "evalue": "ignored", 196 | "output_type": "error", 197 | "traceback": [ 198 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 199 | "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)", 200 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0;31m# The expected output is 2\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m4\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 17\u001b[0;31m \u001b[0;32massert\u001b[0m \u001b[0mcount_positive\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"Test failed: count_positive(%s) == %d\"\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcount_positive\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 201 | "\u001b[0;31mAssertionError\u001b[0m: Test failed: count_positive([-4, 2, 0, 2]) == 3" 202 | ] 203 | } 204 | ], 205 | "source": [ 206 | "'''\n", 207 | " x is a list of integers\n", 208 | " Return the number of _strictly_ positive elements in x.\n", 209 | "'''\n", 210 | "def count_positive(x):\n", 211 | " count = 0\n", 212 | " i = 0\n", 213 | " while i < len(x):\n", 214 | " if x[i] >= 0:\n", 215 | " count += 1\n", 216 | " i += 1\n", 217 | " return count\n", 218 | "\n", 219 | "# The expected output is 2\n", 220 | "x = [-4, 2, 0, 2]\n", 221 | "assert count_positive(x) == 2, \"Test failed: count_positive(%s) == %d\" % (x, count_positive(x))" 222 | ] 223 | } 224 | ], 225 | "metadata": { 226 | "colab": { 227 | "authorship_tag": "ABX9TyPwUfUB9xTPqHy6Q1UKenSH", 228 | "collapsed_sections": [], 229 | "include_colab_link": true, 230 | "name": "SWEN900006 Tutorial 1.ipynb", 231 | "provenance": [], 232 | "toc_visible": true 233 | }, 234 | "kernelspec": { 235 | "display_name": "Python 3", 236 | "name": "python3" 237 | }, 238 | "language_info": { 239 | "name": "python" 240 | } 241 | }, 242 | "nbformat": 4, 243 | "nbformat_minor": 0 244 | } 245 | -------------------------------------------------------------------------------- /SWEN90006_Tutorial_10.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "d8b28f7a", 6 | "metadata": { 7 | "id": "9f6077ed" 8 | }, 9 | "source": [ 10 | "# SWEN90006 Tutorial 10" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "id": "609dd600", 16 | "metadata": { 17 | "id": "59164571" 18 | }, 19 | "source": [ 20 | "## Your Tasks\n", 21 | "\n", 22 | "\n", 23 | "### Question 1\n", 24 | "Consider the function foo in Figure C.4 for checking the values of a given string (i.e. an array of characters). Assume that we run a *dynamic symbolic execution* (DSE) tool on this program, with the initial test being `arr = \"xxxx\"` and `count = 4`. \n", 25 | "\n", 26 | "Specify the path constraint that this will generate. Note that count is a constant.\n", 27 | "\n", 28 | "```c\n", 29 | " 1. int foo(char *arr, const int count) {\n", 30 | " 2. int i = 0; \n", 31 | " 3. for (i = 0; i < count; i++) {\n", 32 | " 4. if (arr[i] == 'A' + i) return i;\n", 33 | " 5. }\n", 34 | " //0x4d4f4f42 is the 4-byte value of the string\n", 35 | " //\"BOOM\" stored in little-endian memory \n", 36 | " 6. if (*(int*)(arr) != 0x4d4f4f42) {\n", 37 | " 7. return i;\n", 38 | " 8. }\n", 39 | " 9. return 0;\n", 40 | " 10. }\n", 41 | "\n", 42 | "```\n", 43 | "\n", 44 | "

Figure C.4: The foo function

\n", 45 | "\n", 46 | "\n", 47 | "### Question 2\n", 48 | "\n", 49 | "Given the same program and the same input in Question 1, what test cases could be generated by a DSE tool?" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": null, 55 | "id": "e826544b", 56 | "metadata": {}, 57 | "outputs": [], 58 | "source": [] 59 | } 60 | ], 61 | "metadata": { 62 | "colab": { 63 | "include_colab_link": true, 64 | "name": "SWEN90006_Tutorial_06.ipynb", 65 | "provenance": [] 66 | }, 67 | "kernelspec": { 68 | "display_name": "Java", 69 | "language": "java", 70 | "name": "java" 71 | }, 72 | "language_info": { 73 | "codemirror_mode": "java", 74 | "file_extension": ".jshell", 75 | "mimetype": "text/x-java-source", 76 | "name": "Java", 77 | "pygments_lexer": "java", 78 | "version": "15.0.2+7-27" 79 | } 80 | }, 81 | "nbformat": 4, 82 | "nbformat_minor": 5 83 | } 84 | -------------------------------------------------------------------------------- /SWEN90006_Tutorial_2.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "27b19e53", 6 | "metadata": { 7 | "colab_type": "text", 8 | "id": "view-in-github" 9 | }, 10 | "source": [ 11 | "\"Open" 12 | ] 13 | }, 14 | { 15 | "cell_type": "markdown", 16 | "id": "ba935bd3", 17 | "metadata": { 18 | "id": "f5185ac9" 19 | }, 20 | "source": [ 21 | "# SWEN90006 Tutorial 2" 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "id": "215b367d", 27 | "metadata": { 28 | "id": "c2e1bd92" 29 | }, 30 | "source": [ 31 | "## Introduction\n", 32 | "The aim of this tutorial is twofold. First, it aims to give you some practise at deriving test cases from specifications. Second, it aims for you to start exploring the limits of your test cases, and of the specifications." 33 | ] 34 | }, 35 | { 36 | "cell_type": "markdown", 37 | "id": "e658dffd", 38 | "metadata": { 39 | "id": "41331ddb" 40 | }, 41 | "source": [ 42 | "## The LWIG Program\n", 43 | "**Input File:** The input file format is as follows. Each line saves\n", 44 | "the data for a single student, which contains several fields.\n", 45 | "Each field is separated by a colon.\n", 46 | "\n", 47 | "Each line consists of the following fields, in order:\n", 48 | "\n", 49 | "- A student number, which must be a 5 digit, 6 digit or 9 digit\n", 50 | " number.\n", 51 | "\n", 52 | "- The student's month of birth, which must be a string of 3 alphabetic\n", 53 | " characters with the first character capitalised and the remaining in\n", 54 | " lower case. That is, it must be from the set:\n", 55 | " \n", 56 | " $$\\{Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec\\}$$\n", 57 | "\n", 58 | "- The day of birth, which must be a number from 1--31 and must be within\n", 59 | " the valid range of days in that month; that is, it cannot be 30\n", 60 | " February, because February never has 30 days.\n", 61 | "\n", 62 | "- The student's surname, which must be a string of alphabetic\n", 63 | " characters all in capitals.\n", 64 | "\n", 65 | "- The first letter of the student's first name, which must be a single\n", 66 | " capitalised alphabetic character.\n", 67 | "\n", 68 | "- The number of lectures that they slept through, which must be an\n", 69 | " integer between 0 and 24 (both inclusive).\n", 70 | "\n", 71 | "If any input row is invalid, the program should print a warning message\n", 72 | "and continue with the next record. If the program encounters a more\n", 73 | "serious problem (e.g. unable to open input file), it will print an error\n", 74 | "message and exit gracefully." 75 | ] 76 | }, 77 | { 78 | "cell_type": "markdown", 79 | "id": "eb507766", 80 | "metadata": { 81 | "id": "84bf0d7f" 82 | }, 83 | "source": [ 84 | "\n", 85 | "**Example 1**. *As an example, suppose we had the following data.*\n", 86 | "\n", 87 | "- *Student number: 12345*\n", 88 | "\n", 89 | "- *Month of Birth: May*\n", 90 | "\n", 91 | "- *Day of Birth: 26*\n", 92 | "\n", 93 | "- *Surname: CHAN*\n", 94 | "\n", 95 | "- *First letter of first name: K*\n", 96 | "\n", 97 | "- *Number of lecture(s) slept through: 0*\n", 98 | "\n", 99 | "*The input line for this data would be `12345:May:26:CHAN:K:0`*" 100 | ] 101 | }, 102 | { 103 | "cell_type": "markdown", 104 | "id": "5d688cf6", 105 | "metadata": { 106 | "id": "dfce6906" 107 | }, 108 | "source": [ 109 | "## Tasks\n", 110 | "\n", 111 | "1. What is the input domain for the LWIG program? What are the input conditions for the LWIG program?\n", 112 | "\n", 113 | "2. Derive input test-cases for the program using equivalence partitioning, draw a test template tree to derive equivalence classes systematically and without overlap. \n", 114 | "\n", 115 | "3. Implement your tests in the JUnit driver below. Do your tests find any faults?\n", 116 | "\n", 117 | "4. We implemented 4 faults in the LWIG program, how many faults did your test reveal? Why does or doesn't equivalence partitioning find all of them? \n", 118 | "\n", 119 | "5. [take home question] Of course, the client has not completely specified the program (but, that is to be expected). There is an additional requirement that the records can be sorted by different output fields.\n", 120 | " What are the implications of sorting on the various fields and what test cases would you choose to ensure that sorting has been correctly implemented?" 121 | ] 122 | }, 123 | { 124 | "cell_type": "markdown", 125 | "id": "07f7c236", 126 | "metadata": { 127 | "id": "863d3328" 128 | }, 129 | "source": [ 130 | "## Java Implementation\n", 131 | "\n", 132 | "The following code is a minimal implementation of the LWIG program. \n", 133 | "\n", 134 | "For the purpose of this tutorial, let's assume that the input file has already been parsed into an array containing the important elements.\n", 135 | "\n", 136 | "### Prepare the Java Kernel\n", 137 | "Since Java is not natively supported by Colab, we need to run the following code to enable Java kernel on Colab.\n", 138 | "\n", 139 | "1. Run the cell bellow (click it and press Shift+Enter),\n", 140 | "2. Change the kernel to java_use (Runtime -> Change Runtime Type -> select **\"java_use\"** -> Save)\n", 141 | "3. Try and run the following cells. The java kernel is ready if the you can load the JUnit library in the following cell. \n", 142 | "\n", 143 | "### Trouble shooting\n", 144 | " * There are two Java runtimes having similar names that you can select in step 2. If you accidentally select **java** instead of **java_use**, Colab will enter an indefinite loop, show **connecting**, and the bottom bar has a message saying \"Connecting to **java_tcp** Google Compute Engine backend\", you should delete the runtime (Runtime -> Disconnect and Delete Runtime), and run step 1 again. \n", 145 | " * The working runtime has a log message saying it is **connecting to java Google Compute Enginge Backend**" 146 | ] 147 | }, 148 | { 149 | "cell_type": "code", 150 | "execution_count": null, 151 | "id": "6defd19e", 152 | "metadata": { 153 | "id": "lHpILvGVHBMq", 154 | "vscode": { 155 | "languageId": "java" 156 | } 157 | }, 158 | "outputs": [], 159 | "source": [ 160 | "%%sh\n", 161 | "# Install java kernel\n", 162 | "wget -q https://github.com/SpencerPark/IJava/releases/download/v1.3.0/ijava-1.3.0.zip \n", 163 | "unzip -q ijava-1.3.0.zip \n", 164 | "python install.py\n", 165 | "\n", 166 | "# Install proxy for the java kernel\n", 167 | "wget -qO- https://gist.github.com/wenta0g/67289a9b2e54b8128109abb3aff2194b/archive/0707f5d61d156ce2830505679994b0f1a606589b.tar.gz | tar xvz --strip-components=1\n", 168 | "python install_ipc_proxy_kernel.py --kernel=java --implementation=ipc_proxy_kernel.py" 169 | ] 170 | }, 171 | { 172 | "cell_type": "code", 173 | "execution_count": null, 174 | "id": "a8f145d0", 175 | "metadata": { 176 | "id": "48be5302", 177 | "vscode": { 178 | "languageId": "java" 179 | } 180 | }, 181 | "outputs": [], 182 | "source": [ 183 | "%%loadFromPOM\n", 184 | "\n", 185 | "\n", 186 | " junit\n", 187 | " junit\n", 188 | " 4.13.2\n", 189 | "" 190 | ] 191 | }, 192 | { 193 | "cell_type": "markdown", 194 | "id": "a525b605", 195 | "metadata": { 196 | "id": "ceCuEzQItVqj" 197 | }, 198 | "source": [ 199 | "## LWIG Implementation\n", 200 | "\n", 201 | "The following is a basic Java implementation of LWIG." 202 | ] 203 | }, 204 | { 205 | "cell_type": "code", 206 | "execution_count": null, 207 | "id": "040f4a27", 208 | "metadata": { 209 | "id": "x_cr17kAD5Id", 210 | "vscode": { 211 | "languageId": "java" 212 | } 213 | }, 214 | "outputs": [], 215 | "source": [ 216 | "import java.time.*;\n", 217 | "import java.time.format.*;\n", 218 | "import java.util.Arrays;\n", 219 | "import java.util.Collection;\n", 220 | "import java.util.Locale;\n", 221 | "\n", 222 | "public class LWIG {\n", 223 | "\n", 224 | " public static boolean isValidDate(String month, String date) {\n", 225 | " boolean isValid = false;\n", 226 | " try {\n", 227 | " DateTimeFormatter dtf = new DateTimeFormatterBuilder()\n", 228 | " .parseCaseInsensitive() \n", 229 | " .appendPattern(\"d-MMM-uuuu\") \n", 230 | " .toFormatter(Locale.ENGLISH);\n", 231 | " LocalDate.parse(String.format(\"%s-%s-2012\", date, month), dtf); // Hard coded a leap year or common year\n", 232 | " isValid = true;\n", 233 | " } catch (Exception e) {\n", 234 | " //e.printStackTrace();\n", 235 | " isValid = false;\n", 236 | " }\n", 237 | " return isValid;\n", 238 | " }\n", 239 | " \n", 240 | " public static boolean isValidID(String id) {\n", 241 | " String regEx = \"^(\\\\d{5}|\\\\d{6}|\\\\d{9}|\\\\d{10})$\"; // \n", 242 | " return id.matches(regEx);\n", 243 | " }\n", 244 | " \n", 245 | " public static boolean isValidSurname(String name)\n", 246 | " {\n", 247 | " String regEx = \"^[A-Z]+$\";\n", 248 | " return name.matches(regEx);\n", 249 | " }\n", 250 | " \n", 251 | " public static boolean isValidFirstLetter(String name)\n", 252 | " {\n", 253 | " String regEx = \"^[A-Z]$\";\n", 254 | " return name.matches(regEx);\n", 255 | " }\n", 256 | " \n", 257 | " public static boolean isValidSleptCount(String number)\n", 258 | " {\n", 259 | " boolean isValid = false;\n", 260 | " try {\n", 261 | " int count = Integer.parseInt(number);\n", 262 | " if (count >= 0 && count < 24) {\n", 263 | " isValid = true;\n", 264 | " }\n", 265 | " } catch (Exception e) {\n", 266 | " isValid = false;\n", 267 | " }\n", 268 | " return isValid;\n", 269 | " }\n", 270 | "}" 271 | ] 272 | }, 273 | { 274 | "cell_type": "markdown", 275 | "id": "0f73bfa9", 276 | "metadata": { 277 | "id": "609de918" 278 | }, 279 | "source": [ 280 | "##JUnit test script\n", 281 | "\n", 282 | "The following code block is a JUnit test script. JUnit is a unit-testing framework for Java that allows you to easily create tests that can be run automatically. \n", 283 | "\n", 284 | "In the code block below, put your test cases where is says \"Your test cases start here\". Add test cases by adding new elements to the data array. These will then be executed automatically by JUnit." 285 | ] 286 | }, 287 | { 288 | "cell_type": "code", 289 | "execution_count": null, 290 | "id": "c2aa73dd", 291 | "metadata": { 292 | "id": "8f47ce10", 293 | "vscode": { 294 | "languageId": "java" 295 | } 296 | }, 297 | "outputs": [], 298 | "source": [ 299 | "import junit.framework.TestCase;\n", 300 | "\n", 301 | "import org.junit.Test;\n", 302 | "import org.junit.runner.*;\n", 303 | "import org.junit.runner.RunWith;\n", 304 | "import org.junit.runner.notification.Failure;\n", 305 | "import org.junit.runners.Parameterized;\n", 306 | "\n", 307 | "@RunWith(Parameterized.class)\n", 308 | "public class LWIGTestCase extends TestCase {\n", 309 | " \n", 310 | " @Parameterized.Parameter(0)\n", 311 | " public String id;\n", 312 | " @Parameterized.Parameter(1)\n", 313 | " public String month;\n", 314 | " @Parameterized.Parameter(2)\n", 315 | " public String date;\n", 316 | " @Parameterized.Parameter(3)\n", 317 | " public String surname;\n", 318 | " @Parameterized.Parameter(4)\n", 319 | " public String firstLetter;\n", 320 | " @Parameterized.Parameter(5)\n", 321 | " public String sleptCount;\n", 322 | " @Parameterized.Parameter(6)\n", 323 | " public boolean result;\n", 324 | " \n", 325 | " @Test\n", 326 | " public void testLWIG() {\n", 327 | " boolean expectedResult = LWIG.isValidID(id) &&\n", 328 | " LWIG.isValidDate(month, date) &&\n", 329 | " LWIG.isValidSurname(surname) &&\n", 330 | " LWIG.isValidFirstLetter(firstLetter) &&\n", 331 | " LWIG.isValidSleptCount(sleptCount);\n", 332 | " assertEquals(result, expectedResult);\n", 333 | " }\n", 334 | "\n", 335 | " @Parameterized.Parameters(name = \"Test case {index} failed: LWIG with id = {0}, Mon = {1}, date = {2}, surname = {3}, first letter = {4}, slept count = {5}, expected result = {6}\")\n", 336 | " public static Collection data() {\n", 337 | " Object[][] data = new Object[][]{\n", 338 | " // Your Test cases start here\n", 339 | " {\"13456\", \"Jan\", \"30\", \"CHAN\", \"K\", \"1\", true}, \n", 340 | " {\"12345678\", \"Feb\", \"26\", \"TOM\", \"3\", \"0\", true}\n", 341 | " // Your Test cases end here\n", 342 | " };\n", 343 | " return Arrays.asList(data);\n", 344 | " }\n", 345 | "}" 346 | ] 347 | }, 348 | { 349 | "cell_type": "code", 350 | "execution_count": null, 351 | "id": "5f33ab70", 352 | "metadata": { 353 | "id": "eirtRU97oeUx", 354 | "vscode": { 355 | "languageId": "java" 356 | } 357 | }, 358 | "outputs": [], 359 | "source": [ 360 | "Result result = JUnitCore.runClasses(LWIGTestCase.class);\n", 361 | "for (Failure failure : result.getFailures()) {\n", 362 | " System.out.println(failure.toString());\n", 363 | "}\n", 364 | "System.out.println(String.format(\"Total run count: %s, Failed run count: %s\", result.getRunCount(), result.getFailureCount()));" 365 | ] 366 | }, 367 | { 368 | "cell_type": "code", 369 | "execution_count": null, 370 | "id": "889ce680", 371 | "metadata": { 372 | "vscode": { 373 | "languageId": "java" 374 | } 375 | }, 376 | "outputs": [], 377 | "source": [] 378 | } 379 | ], 380 | "metadata": { 381 | "colab": { 382 | "include_colab_link": true, 383 | "name": "Tutorial_02_LWIG.ipynb", 384 | "provenance": [] 385 | }, 386 | "kernelspec": { 387 | "display_name": "Java", 388 | "language": "java", 389 | "name": "java" 390 | }, 391 | "language_info": { 392 | "codemirror_mode": "java", 393 | "file_extension": ".jshell", 394 | "mimetype": "text/x-java-source", 395 | "name": "Java", 396 | "pygments_lexer": "java", 397 | "version": "10.0.2+13" 398 | } 399 | }, 400 | "nbformat": 4, 401 | "nbformat_minor": 5 402 | } 403 | -------------------------------------------------------------------------------- /SWEN90006_Tutorial_3.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "colab_type": "text", 7 | "id": "view-in-github" 8 | }, 9 | "source": [ 10 | "\"Open" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": { 16 | "id": "ecf80d1c" 17 | }, 18 | "source": [ 19 | "# SWEN90006 Tutorial 3" 20 | ] 21 | }, 22 | { 23 | "cell_type": "markdown", 24 | "metadata": { 25 | "id": "8265c408" 26 | }, 27 | "source": [ 28 | "## Introduction\n", 29 | "The aim of this tutorial is for you to familiarise yourself with the\n", 30 | "various coverage criteria and analysis of the program for the various\n", 31 | "coverage criteria. When you get back to your revision you should try\n", 32 | "comparing the test cases that you derive for a program using different\n", 33 | "techniques.\n", 34 | "\n", 35 | "The different type of program that we encounter this week is a numerical\n", 36 | "program. One of the challenges of numerical programs is that we can\n", 37 | "never be certain that we will get an *exact* answer to our computation.\n", 38 | "Instead what we typically require is an answer to within some *error*\n", 39 | "value. (Recall from the lecture notes that an error is the difference between a computed value and the exact value). Numerical programs are tricky to debug, because they are\n", 40 | "often used to *find* the answer to some problem in the first place. For\n", 41 | "example, solving some integration or differentiation problems is too\n", 42 | "hard to do by hand and so we use a *numerical* method to approximate the\n", 43 | "answer." 44 | ] 45 | }, 46 | { 47 | "cell_type": "markdown", 48 | "metadata": { 49 | "id": "a0fd58b6" 50 | }, 51 | "source": [ 52 | "## Working With the Program\n", 53 | "The program implements the standard bisection method for root finding.\n", 54 | "The root-finding problem is expressed as follows:\n", 55 | "\n", 56 | "> We are given a function $f(x)$ taking a real number and returning a\n", 57 | "> real number; that is a function $f: \\mathbb{R} \\rightarrow \\mathbb{R}$. The function is negative at some point $x_0$ and\n", 58 | "> positive at some point $x_1$. Find the value $x$ for which $f(x) = 0$\n", 59 | "> on an interval $[Lower,Upper]$. The point $x$ is a root of $f$ on the\n", 60 | "> interval $[Lower,Upper]$.\n", 61 | "\n", 62 | "As an example, consider the natural logarithm function, $ln$. The graph\n", 63 | "in Figure 1 shows the values of $ln(x)$ for various values\n", 64 | "of $x$. We can see that the value of $ln(x)$ is equal to 0 when $x=1$.\n", 65 | "The bisection algorithm finds this value of $x$.\n", 66 | "\n", 67 | "\n", 68 | "\n", 69 | "
Figure 1: Root finding problems.
\n", 70 | "\n", 71 | "The idea behind the algorithm for finding roots is to look at the\n", 72 | "interval $[Lower,Upper]$ and bisect it (hence the name of the algorithm)\n", 73 | "and find the midpoint of the interval $x_r$. If we know that\n", 74 | "$f(\\mathit{Lower})$ is negative, and $f(\\mathit{Upper})$ is positive\n", 75 | "then there must be root in the interval, provided that the function is\n", 76 | "continuous. If the value of $f$ at $x_r$ is positive then the root must\n", 77 | "be in the interval $[Lower,x_r]$. If the value of $f$ at $x_r$ is\n", 78 | "negative then the root must be in the interval $[x_r,Upper]$. The\n", 79 | "algorithm should converge to the root because the length of the interval\n", 80 | "is getting smaller every time (in fact the length of the interval is\n", 81 | "halved every time). Does this sound familiar?" 82 | ] 83 | }, 84 | { 85 | "cell_type": "markdown", 86 | "metadata": { 87 | "id": "92b1db19" 88 | }, 89 | "source": [ 90 | "## Your Tasks\n", 91 | "\n", 92 | "1. What is the input domain for the `Bisection` program below?\n", 93 | "\n", 94 | "2. Draw the control-flow graph for the `Bisection` function. You may break the function up into basic blocks to simplify your CFG.\n", 95 | "\n", 96 | " **Recall** that a *basic block* is a continuous sequence of statements where control flows from one statement to the next, a single point of entry, a single point of exit and no branches or loops.\n", 97 | "\n", 98 | "3. Suppose that we concentrated on the (nice and linear) function $f(x) = x - 2$. Derive a set of test cases that achieve:\n", 99 | " - Statement coverage; and\n", 100 | " - Condition coverage.\n", 101 | " \n", 102 | " Note that you will have to determine what it means for the `Bisection` function to return the *correct* or *expected* output first.\n", 103 | "\n", 104 | "4. **Extended task**: After the tutorial, try implementing the tests in the JUnit driver below." 105 | ] 106 | }, 107 | { 108 | "cell_type": "markdown", 109 | "metadata": { 110 | "id": "804378d0" 111 | }, 112 | "source": [ 113 | "## The Program\n", 114 | "\n", 115 | "### Prepare the Java Kernel\n", 116 | "Since Java is not natively supported by Colab, we need to run the following code to enable Java kernel on Colab.\n", 117 | "\n", 118 | "1. Run the cell bellow (click it and press Shift+Enter),\n", 119 | "2. Change the kernel to java_use (Runtime -> Change Runtime Type -> select **\"java_use\"** -> Save)\n", 120 | "3. Try and run the following cells. The java kernel is ready if the you can load the JUnit library in the following cell. \n", 121 | "\n", 122 | "### Trouble shooting\n", 123 | " * There are two Java runtimes having similar names that you can select in step 2. If you accidentally select **java** instead of **java_use**, Colab will enter an indefinite loop, show **connecting**, and the bottom bar has a message saying \"Connecting to **java_tcp** Google Compute Engine backend\", you should delete the runtime (Runtime -> Disconnect and Delete Runtime), and run step 1 again. \n", 124 | " * The working runtime has a log message saying it is **connecting to java Google Compute Enginge Backend**" 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": null, 130 | "metadata": { 131 | "id": "d5161ba0", 132 | "vscode": { 133 | "languageId": "java" 134 | } 135 | }, 136 | "outputs": [], 137 | "source": [ 138 | "%%sh\n", 139 | "# Install java kernel\n", 140 | "wget -q https://github.com/SpencerPark/IJava/releases/download/v1.3.0/ijava-1.3.0.zip \n", 141 | "unzip -q ijava-1.3.0.zip \n", 142 | "python install.py\n", 143 | "\n", 144 | "# Install proxy for the java kernel\n", 145 | "wget -qO- https://gist.github.com/wenta0g/67289a9b2e54b8128109abb3aff2194b/archive/0707f5d61d156ce2830505679994b0f1a606589b.tar.gz | tar xvz --strip-components=1\n", 146 | "python install_ipc_proxy_kernel.py --kernel=java --implementation=ipc_proxy_kernel.py" 147 | ] 148 | }, 149 | { 150 | "cell_type": "code", 151 | "execution_count": null, 152 | "metadata": { 153 | "id": "bc13d44e", 154 | "vscode": { 155 | "languageId": "java" 156 | } 157 | }, 158 | "outputs": [], 159 | "source": [ 160 | "%%loadFromPOM\n", 161 | "\n", 162 | "\n", 163 | " junit\n", 164 | " junit\n", 165 | " 4.13.2\n", 166 | "" 167 | ] 168 | }, 169 | { 170 | "cell_type": "markdown", 171 | "metadata": { 172 | "id": "26a8ba1c" 173 | }, 174 | "source": [ 175 | "The following is a basic Java implementation of `Bisection`." 176 | ] 177 | }, 178 | { 179 | "cell_type": "code", 180 | "execution_count": null, 181 | "metadata": { 182 | "id": "625430b8", 183 | "vscode": { 184 | "languageId": "java" 185 | } 186 | }, 187 | "outputs": [], 188 | "source": [ 189 | "public class Bisection{\n", 190 | "\n", 191 | " static final int MAX_INT = 65535;\n", 192 | " \n", 193 | " static double bisection(double lower, double upper, double error, int max) {\n", 194 | " \n", 195 | " double sign = 0.0; /* Test for the sign of the midpoint xr. */\n", 196 | " double ea = MAX_INT; /* Calculated error value. */\n", 197 | " double xrold = 0.0; /* Previous estimate. */\n", 198 | " double xr = 0.0; /* Current x estimate for the root. */\n", 199 | " double fr = 0.0; /* Current value of f. */\n", 200 | " double fl = 0.0; /* Value of f at the lower end of the interval. */\n", 201 | " int iteration = 0; /* For keeping track of the number of iterations. */\n", 202 | " \n", 203 | " fl = func(lower);\n", 204 | " while ((ea > error && iteration < max)) {\n", 205 | " \n", 206 | " /* Start by memorising the old estimate in xrold and then calculate\n", 207 | " the new estimate and store in fr */\n", 208 | " xrold = xr;\n", 209 | " xr = (lower + upper) / 2;\n", 210 | " fr = func(xr);\n", 211 | " iteration++;\n", 212 | " /* Estimate the percentage error and store in ea. */\n", 213 | " if (xr != 0) {\n", 214 | " ea = Math.abs((xr - xrold)/xr) * 100;\n", 215 | " }\n", 216 | " \n", 217 | " /* To know whether fr has the same sign as f(Lower) or f(Upper) is easy:\n", 218 | " we know that f(Lower) is negative and we know that f(Upper) is positive.\n", 219 | " Multiple fr by f(Lower) and if the result is positive then fr must be\n", 220 | " negative. If the result is negative then fr must be positive. */\n", 221 | " \n", 222 | " sign = func(lower) * fr;\n", 223 | " if (sign < 0)\n", 224 | " upper = xr;\n", 225 | " else if (sign > 0)\n", 226 | " lower = xr;\n", 227 | " else\n", 228 | " ea = 0;\n", 229 | " System.out.println(String.format(\"iteration %d = (%f, %f, %f, %f, %f)\\n\", iteration, lower, upper, xr, ea, sign));\n", 230 | " }\n", 231 | " return xr;\n", 232 | " }\n", 233 | " \n", 234 | " static double func(double x) {\n", 235 | " return x - 2;\n", 236 | " }\n", 237 | "}" 238 | ] 239 | }, 240 | { 241 | "cell_type": "markdown", 242 | "metadata": { 243 | "id": "7f61a27e" 244 | }, 245 | "source": [ 246 | "## JUnit test script\n", 247 | "\n", 248 | "The following code block is a JUnit test script. JUnit is a unit-testing framework for Java that allows you to easily create tests that can be run automatically. \n", 249 | "\n", 250 | "In the code block below, put your test cases where is says \"Your test cases start here\". Add test cases by adding new elements to the data array. These will then be executed automatically by JUnit." 251 | ] 252 | }, 253 | { 254 | "cell_type": "code", 255 | "execution_count": null, 256 | "metadata": { 257 | "id": "7ed1cef5", 258 | "vscode": { 259 | "languageId": "java" 260 | } 261 | }, 262 | "outputs": [], 263 | "source": [ 264 | "import java.util.Arrays;\n", 265 | "import java.util.Collection;\n", 266 | "\n", 267 | "import org.junit.Test;\n", 268 | "import org.junit.runner.JUnitCore;\n", 269 | "import org.junit.runner.Result;\n", 270 | "import org.junit.runner.RunWith;\n", 271 | "import org.junit.runner.notification.Failure;\n", 272 | "import org.junit.runners.Parameterized;\n", 273 | "\n", 274 | "import junit.framework.TestCase;\n", 275 | "\n", 276 | "@RunWith(Parameterized.class)\n", 277 | "public class TestBisection extends TestCase {\n", 278 | " \n", 279 | " @Parameterized.Parameter(0)\n", 280 | " public double lower;\n", 281 | " @Parameterized.Parameter(1)\n", 282 | " public double upper;\n", 283 | " @Parameterized.Parameter(2)\n", 284 | " public double error;\n", 285 | " @Parameterized.Parameter(3)\n", 286 | " public int max;\n", 287 | " @Parameterized.Parameter(4)\n", 288 | " public double results;\n", 289 | "\n", 290 | " @Parameterized.Parameters(name = \"{index}: lower: {0} upper:{1} error:{2} iterations:{3} results:{5}\")\n", 291 | " public static Collection data() {\n", 292 | " Object[][] data = new Object[][]{\n", 293 | " // Your Test cases start here\n", 294 | " // Please follow the pattern: lower, upper, error, iterations, expected results\n", 295 | " {-1.0, 7.0, 1, 10, 2.0},\n", 296 | " {-1.0, 7.0, 1, 10, 2.0}\n", 297 | " // Your Test cases end here\n", 298 | " };\n", 299 | " return Arrays.asList(data);\n", 300 | " }\n", 301 | "\n", 302 | " @Test\n", 303 | " public void testBisection() {\n", 304 | " assertEquals(results, Bisection.bisection(lower, upper, error, max));\n", 305 | " }\n", 306 | "}" 307 | ] 308 | }, 309 | { 310 | "cell_type": "code", 311 | "execution_count": null, 312 | "metadata": { 313 | "id": "eb0485b6", 314 | "outputId": "ce74d455-7585-4ee9-eadd-ab4e213f9304", 315 | "scrolled": false, 316 | "vscode": { 317 | "languageId": "java" 318 | } 319 | }, 320 | "outputs": [ 321 | { 322 | "name": "stdout", 323 | "output_type": "stream", 324 | "text": [ 325 | "iteration 1 = (-1.000000, 3.000000, 3.000000, 100.000000, -3.000000)\n", 326 | "\n", 327 | "iteration 2 = (1.000000, 3.000000, 1.000000, 200.000000, 3.000000)\n", 328 | "\n", 329 | "iteration 3 = (1.000000, 3.000000, 2.000000, 0.000000, -0.000000)\n", 330 | "\n", 331 | "iteration 1 = (-1.000000, 3.000000, 3.000000, 100.000000, -3.000000)\n", 332 | "\n", 333 | "iteration 2 = (1.000000, 3.000000, 1.000000, 200.000000, 3.000000)\n", 334 | "\n", 335 | "iteration 3 = (1.000000, 3.000000, 2.000000, 0.000000, -0.000000)\n", 336 | "\n", 337 | "Total run count: 2, Failed run count: 0\n" 338 | ] 339 | } 340 | ], 341 | "source": [ 342 | "Result result = JUnitCore.runClasses(TestBisection.class);\n", 343 | "for (Failure failure : result.getFailures()) {\n", 344 | " System.out.println(failure.toString());\n", 345 | "}\n", 346 | "System.out.println(String.format(\"Total run count: %s, Failed run count: %s\", result.getRunCount(), result.getFailureCount()));" 347 | ] 348 | } 349 | ], 350 | "metadata": { 351 | "colab": { 352 | "include_colab_link": true, 353 | "name": "Tutorial_02_LWIG.ipynb", 354 | "provenance": [] 355 | }, 356 | "kernelspec": { 357 | "display_name": "Java", 358 | "language": "java", 359 | "name": "java" 360 | }, 361 | "language_info": { 362 | "codemirror_mode": "java", 363 | "file_extension": ".jshell", 364 | "mimetype": "text/x-java-source", 365 | "name": "Java", 366 | "pygments_lexer": "java", 367 | "version": "10.0.2+13" 368 | } 369 | }, 370 | "nbformat": 4, 371 | "nbformat_minor": 5 372 | } 373 | -------------------------------------------------------------------------------- /SWEN90006_Tutorial_3_2024.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "\"Open" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "# SWEN90006 Tutorial 3" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "## Introduction\n", 22 | "The aim of this tutorial is twofold. \n", 23 | "\n", 24 | "First, we use last week's LWIG Program to perform bounary value analysis. \n", 25 | "\n", 26 | "Second, you can familiarise yourself with the terms used when describing the source code under test, draw control flow graphs, and briefly touch on coverage-based criteria. " 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "metadata": {}, 32 | "source": [ 33 | "# Part 1: Boundary-Value Analysis\n", 34 | "\n", 35 | "Recap on the guidelines to derive test cases using boundary value analysis. \n", 36 | "\n", 37 | "## Your tasks:\n", 38 | "\n", 39 | "1. Using the table below, given the domain boundary to test, find on points and off points of all the boundaries. \n", 40 | "\n", 41 | "\n", 42 | " | input | domain boundary | \n", 43 | " | ----------- | --------------- |\n", 44 | " | integer i | i = 4 |\n", 45 | " | integer i | i <= 15 |\n", 46 | " | integer i | i > 10 |\n", 47 | " | char c | 'a' <= c <= 'z' (use ASCII code) |\n", 48 | " | string s | s = \"TEST\" |\n", 49 | "\n", 50 | "\n", 51 | "\n", 52 | "2. Recall the LWIG program from last week, derive test cases using boundary value analysis for the following Equivalence classes. For simplisity, you only need to consider the boundary related to input Date. \n", 53 | "\n", 54 | " EC7; having length[s] = 6, Month = Feb, Date < 1 \n", 55 | "\n", 56 | " EC8; having length[s] = 6, Month = Feb, Date $\\in$ [1,29]\n", 57 | "\n", 58 | " EC9; having length[s] = 6, Month = Feb, Date > 29\n", 59 | "\n", 60 | "\n", 61 | "\n", 62 | "3. \\[take home\\] Derive test cases using boundary value analysis for the rest of equivalent classes identified last week. \n", 63 | "\n", 64 | "\n" 65 | ] 66 | }, 67 | { 68 | "cell_type": "markdown", 69 | "metadata": {}, 70 | "source": [ 71 | "# Part 2: Control Flow Testing" 72 | ] 73 | }, 74 | { 75 | "cell_type": "markdown", 76 | "metadata": {}, 77 | "source": [ 78 | "We have a different type of program under test this week, which is a numerical\n", 79 | "program. One of the challenges of numerical programs is that we can\n", 80 | "never be certain that we will get an *exact* answer to our computation.\n", 81 | "Instead what we typically require is an answer within some *error*\n", 82 | "margin. Numerical programs are tricky to debug, because there may not exists a golden rule to *find* the expected output of the program. For\n", 83 | "example, solving some integration or differentiation problems is too\n", 84 | "hard to do by hand and so we use a *numerical* method to approximate the\n", 85 | "answer. Depending on the methods of your apporximation, the actual output may not be predictable" 86 | ] 87 | }, 88 | { 89 | "cell_type": "markdown", 90 | "metadata": {}, 91 | "source": [ 92 | "## Working With the Program\n", 93 | "The program implements the standard bisection method for root finding.\n", 94 | "The root-finding problem is expressed as follows:\n", 95 | "\n", 96 | "> We are given a function $f(x)$ taking a real number and returning a\n", 97 | "> real number; that is a function $f: \\mathbb{R} \\rightarrow \\mathbb{R}$. The function is negative at some point $x_0$ and\n", 98 | "> positive at some point $x_1$. Find the value $x$ for which $f(x) = 0$\n", 99 | "> on an interval $[Lower,Upper]$. The point $x$ is a root of $f$ on the\n", 100 | "> interval $[Lower,Upper]$.\n", 101 | "\n", 102 | "As an example, consider the natural logarithm function, $ln$. The graph\n", 103 | "in Figure 1 shows the values of $ln(x)$ for various values\n", 104 | "of $x$. We can see that the value of $ln(x)$ is equal to 0 when $x=1$.\n", 105 | "The bisection algorithm finds this value of $x$.\n", 106 | "\n", 107 | "\n", 108 | "\n", 109 | "
Figure 1: Root finding problems.
\n", 110 | "\n", 111 | "The idea behind the algorithm for finding roots is to look at the\n", 112 | "interval $[Lower,Upper]$ and bisect it (hence the name of the algorithm)\n", 113 | "and find the midpoint of the interval $x_r$. If we know that\n", 114 | "$f(\\mathit{Lower})$ is negative, and $f(\\mathit{Upper})$ is positive\n", 115 | "then there must be root in the interval, provided that the function is\n", 116 | "continuous. If the value of $f$ at $x_r$ is positive then the root must\n", 117 | "be in the interval $[Lower,x_r]$. If the value of $f$ at $x_r$ is\n", 118 | "negative then the root must be in the interval $[x_r,Upper]$. The\n", 119 | "algorithm should converge to the root because the length of the interval\n", 120 | "is getting smaller every time (in fact the length of the interval is\n", 121 | "halved every time). Does this sound familiar?" 122 | ] 123 | }, 124 | { 125 | "cell_type": "markdown", 126 | "metadata": {}, 127 | "source": [ 128 | "## Your Tasks\n", 129 | "\n", 130 | "\n", 131 | "1. What is the input domain for the `Bisection` program below?\n", 132 | "\n", 133 | "2. Draw the control-flow graph for the `Bisection` function. You may break the function up into basic blocks to simplify your CFG.\n", 134 | "\n", 135 | " **Recall** that a *basic block* is a continuous sequence of statements where control flows from one statement to the next, a single point of entry, a single point of exit and no branches or loops.\n", 136 | "\n", 137 | "3. Suppose that we concentrated on the (nice and linear) function $f(x) = x - 2$. Derive a set of test cases that can:\n", 138 | " - Execute every statement of the program under test at least once. Formally we call it achieving 100% statement coverage \n", 139 | " - Each condition if a branch is made to evaluate to true and false at least once. Formally we call it achieving 100% condition coverage. \n", 140 | " \n", 141 | " Note that you will have to determine what it means for the `Bisection` function to return the *correct* or *expected* output first.\n", 142 | "\n", 143 | "4. **Extended task**: After the tutorial, try implementing the tests in the JUnit driver below." 144 | ] 145 | }, 146 | { 147 | "cell_type": "markdown", 148 | "metadata": {}, 149 | "source": [ 150 | "## The Program\n", 151 | "\n", 152 | "### Prepare the Java Kernel\n", 153 | "Since Java is not natively supported by Colab, we need to run the following code to enable Java kernel on Colab.\n", 154 | "\n", 155 | "1. Run the cell bellow (click it and press Shift+Enter),\n", 156 | "2. Change the kernel to java_use (Runtime -> Change Runtime Type -> select **\"java_use\"** -> Save)\n", 157 | "3. Try and run the following cells. The java kernel is ready if the you can load the JUnit library in the following cell. \n", 158 | "\n", 159 | "### Trouble shooting\n", 160 | " * There are two Java runtimes having similar names that you can select in step 2. If you accidentally select **java** instead of **java_use**, Colab will enter an indefinite loop, show **connecting**, and the bottom bar has a message saying \"Connecting to **java_tcp** Google Compute Engine backend\", you should delete the runtime (Runtime -> Disconnect and Delete Runtime), and run step 1 again. \n", 161 | " * The working runtime has a log message saying it is **connecting to java Google Compute Enginge Backend**\n", 162 | " * There are cases if you colab display is not in English, the behaviour " 163 | ] 164 | }, 165 | { 166 | "cell_type": "code", 167 | "execution_count": null, 168 | "metadata": { 169 | "vscode": { 170 | "languageId": "java" 171 | } 172 | }, 173 | "outputs": [], 174 | "source": [ 175 | "%%sh\n", 176 | "# Install java kernel\n", 177 | "wget -q https://github.com/SpencerPark/IJava/releases/download/v1.3.0/ijava-1.3.0.zip \n", 178 | "unzip -q ijava-1.3.0.zip \n", 179 | "python install.py\n", 180 | "\n", 181 | "# Install proxy for the java kernel\n", 182 | "wget -qO- https://gist.github.com/wenta0g/67289a9b2e54b8128109abb3aff2194b/archive/0707f5d61d156ce2830505679994b0f1a606589b.tar.gz | tar xvz --strip-components=1\n", 183 | "python install_ipc_proxy_kernel.py --kernel=java --implementation=ipc_proxy_kernel.py" 184 | ] 185 | }, 186 | { 187 | "cell_type": "code", 188 | "execution_count": null, 189 | "metadata": { 190 | "vscode": { 191 | "languageId": "java" 192 | } 193 | }, 194 | "outputs": [], 195 | "source": [ 196 | "%%loadFromPOM\n", 197 | "\n", 198 | "\n", 199 | " junit\n", 200 | " junit\n", 201 | " 4.13.2\n", 202 | "" 203 | ] 204 | }, 205 | { 206 | "cell_type": "markdown", 207 | "metadata": {}, 208 | "source": [ 209 | "The following is a basic Java implementation of `Bisection`." 210 | ] 211 | }, 212 | { 213 | "cell_type": "code", 214 | "execution_count": null, 215 | "metadata": { 216 | "vscode": { 217 | "languageId": "java" 218 | } 219 | }, 220 | "outputs": [], 221 | "source": [ 222 | "public class Bisection{\n", 223 | "\n", 224 | " static final int MAX_INT = 65535;\n", 225 | " \n", 226 | " static double bisection(double lower, double upper, double error, int max) {\n", 227 | " \n", 228 | " double sign = 0.0; /* Test for the sign of the midpoint xr. */\n", 229 | " double ea = MAX_INT; /* Calculated error value. */\n", 230 | " double xrold = 0.0; /* Previous estimate. */\n", 231 | " double xr = 0.0; /* Current x estimate for the root. */\n", 232 | " double fr = 0.0; /* Current value of f. */\n", 233 | " double fl = 0.0; /* Value of f at the lower end of the interval. */\n", 234 | " int iteration = 0; /* For keeping track of the number of iterations. */\n", 235 | " \n", 236 | " fl = func(lower);\n", 237 | " while ((ea > error && iteration < max)) {\n", 238 | " \n", 239 | " /* Start by memorising the old estimate in xrold and then calculate\n", 240 | " the new estimate and store in fr */\n", 241 | " xrold = xr;\n", 242 | " xr = (lower + upper) / 2;\n", 243 | " fr = func(xr);\n", 244 | " iteration++;\n", 245 | " /* Estimate the percentage error and store in ea. */\n", 246 | " if (xr != 0) {\n", 247 | " ea = Math.abs((xr - xrold)/xr) * 100;\n", 248 | " }\n", 249 | " \n", 250 | " /* To know whether fr has the same sign as f(Lower) or f(Upper) is easy:\n", 251 | " we know that f(Lower) is negative and we know that f(Upper) is positive.\n", 252 | " Multiple fr by f(Lower) and if the result is positive then fr must be\n", 253 | " negative. If the result is negative then fr must be positive. */\n", 254 | " \n", 255 | " sign = func(lower) * fr;\n", 256 | " if (sign < 0)\n", 257 | " upper = xr;\n", 258 | " else if (sign > 0)\n", 259 | " lower = xr;\n", 260 | " else\n", 261 | " ea = 0;\n", 262 | " System.out.println(String.format(\"iteration %d = (%f, %f, %f, %f, %f)\\n\", iteration, lower, upper, xr, ea, sign));\n", 263 | " }\n", 264 | " return xr;\n", 265 | " }\n", 266 | " \n", 267 | " static double func(double x) {\n", 268 | " return x - 2;\n", 269 | " }\n", 270 | "}" 271 | ] 272 | }, 273 | { 274 | "cell_type": "markdown", 275 | "metadata": {}, 276 | "source": [ 277 | "## JUnit test script\n", 278 | "\n", 279 | "The following code block is a JUnit test script. JUnit is a unit-testing framework for Java that allows you to easily create tests that can be run automatically. \n", 280 | "\n", 281 | "In the code block below, put your test cases where is says \"Your test cases start here\". Add test cases by adding new elements to the data array. These will then be executed automatically by JUnit." 282 | ] 283 | }, 284 | { 285 | "cell_type": "code", 286 | "execution_count": null, 287 | "metadata": { 288 | "vscode": { 289 | "languageId": "java" 290 | } 291 | }, 292 | "outputs": [], 293 | "source": [ 294 | "import java.util.Arrays;\n", 295 | "import java.util.Collection;\n", 296 | "\n", 297 | "import org.junit.Test;\n", 298 | "import org.junit.runner.JUnitCore;\n", 299 | "import org.junit.runner.Result;\n", 300 | "import org.junit.runner.RunWith;\n", 301 | "import org.junit.runner.notification.Failure;\n", 302 | "import org.junit.runners.Parameterized;\n", 303 | "\n", 304 | "import junit.framework.TestCase;\n", 305 | "\n", 306 | "@RunWith(Parameterized.class)\n", 307 | "public class TestBisection extends TestCase {\n", 308 | " \n", 309 | " @Parameterized.Parameter(0)\n", 310 | " public double lower;\n", 311 | " @Parameterized.Parameter(1)\n", 312 | " public double upper;\n", 313 | " @Parameterized.Parameter(2)\n", 314 | " public double error;\n", 315 | " @Parameterized.Parameter(3)\n", 316 | " public int max;\n", 317 | " @Parameterized.Parameter(4)\n", 318 | " public double results;\n", 319 | "\n", 320 | " @Parameterized.Parameters(name = \"{index}: lower: {0} upper:{1} error:{2} iterations:{3} results:{5}\")\n", 321 | " public static Collection data() {\n", 322 | " Object[][] data = new Object[][]{\n", 323 | " // Your Test cases start here\n", 324 | " // Please follow the pattern: lower, upper, error, iterations, expected results\n", 325 | " {-1.0, 7.0, 1, 10, 2.0},\n", 326 | " {-1.0, 7.0, 1, 10, 2.0}\n", 327 | " // Your Test cases end here\n", 328 | " };\n", 329 | " return Arrays.asList(data);\n", 330 | " }\n", 331 | "\n", 332 | " @Test\n", 333 | " public void testBisection() {\n", 334 | " assertEquals(results, Bisection.bisection(lower, upper, error, max));\n", 335 | " }\n", 336 | "}" 337 | ] 338 | }, 339 | { 340 | "cell_type": "code", 341 | "execution_count": null, 342 | "metadata": { 343 | "vscode": { 344 | "languageId": "java" 345 | } 346 | }, 347 | "outputs": [ 348 | { 349 | "name": "stdout", 350 | "output_type": "stream", 351 | "text": [ 352 | "iteration 1 = (-1.000000, 3.000000, 3.000000, 100.000000, -3.000000)\n", 353 | "\n", 354 | "iteration 2 = (1.000000, 3.000000, 1.000000, 200.000000, 3.000000)\n", 355 | "\n", 356 | "iteration 3 = (1.000000, 3.000000, 2.000000, 0.000000, -0.000000)\n", 357 | "\n", 358 | "iteration 1 = (-1.000000, 3.000000, 3.000000, 100.000000, -3.000000)\n", 359 | "\n", 360 | "iteration 2 = (1.000000, 3.000000, 1.000000, 200.000000, 3.000000)\n", 361 | "\n", 362 | "iteration 3 = (1.000000, 3.000000, 2.000000, 0.000000, -0.000000)\n", 363 | "\n", 364 | "Total run count: 2, Failed run count: 0\n" 365 | ] 366 | } 367 | ], 368 | "source": [ 369 | "Result result = JUnitCore.runClasses(TestBisection.class);\n", 370 | "for (Failure failure : result.getFailures()) {\n", 371 | " System.out.println(failure.toString());\n", 372 | "}\n", 373 | "System.out.println(String.format(\"Total run count: %s, Failed run count: %s\", result.getRunCount(), result.getFailureCount()));" 374 | ] 375 | } 376 | ], 377 | "metadata": { 378 | "language_info": { 379 | "name": "python" 380 | } 381 | }, 382 | "nbformat": 4, 383 | "nbformat_minor": 2 384 | } 385 | -------------------------------------------------------------------------------- /SWEN90006_Tutorial_4.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "colab_type": "text", 7 | "id": "view-in-github" 8 | }, 9 | "source": [ 10 | "\"Open" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "id": "64f8c7b9", 16 | "metadata": { 17 | "id": "64f8c7b9" 18 | }, 19 | "source": [ 20 | "# SWEN90006 Tutorial 4" 21 | ] 22 | }, 23 | { 24 | "cell_type": "markdown", 25 | "id": "5d778b91", 26 | "metadata": { 27 | "id": "5d778b91" 28 | }, 29 | "source": [ 30 | "## Introduction\n", 31 | "The purpose of this tutorial is for you to gain a deeper understanding\n", 32 | "of control- and data-flow techniques, and to compare these to input\n", 33 | "partitioning techniques." 34 | ] 35 | }, 36 | { 37 | "cell_type": "markdown", 38 | "id": "78f1bb8a", 39 | "metadata": { 40 | "id": "78f1bb8a" 41 | }, 42 | "source": [ 43 | "## Working With the Program\n", 44 | "In this tutorial we will focus on the procedure `bubble`, found in\n", 45 | "Figure 1. The program below serves to show you how we\n", 46 | "intend to use `bubble`. Of course, `bubble` implements a bubble sort.\n", 47 | "\n", 48 | "Make special note of the third parameter to `bubble`, called `order`. This parameter allows us to create a flexible sorting algorithm, which can be used to sort in either ascending or descending order. Both functions `up` and `down` take two integers and return an integer (which is intended to be a boolean value). For this tutorial consider\n", 49 | "just\n", 50 | "\n", 51 | "```java\n", 52 | "public static boolean up(int A, int B) {\n", 53 | " return A < B;\n", 54 | "}\n", 55 | "```\n", 56 | "\n", 57 | "and\n", 58 | "\n", 59 | "```java\n", 60 | "public static boolean down(int A, int B) {\n", 61 | " return B < A;\n", 62 | "}\n", 63 | "```" 64 | ] 65 | }, 66 | { 67 | "cell_type": "markdown", 68 | "id": "f486e92f", 69 | "metadata": { 70 | "id": "f486e92f" 71 | }, 72 | "source": [ 73 | "### Prepare the Java Kernel\n", 74 | "Since Java is not natively supported by Colab, we need to run the following code to enable Java kernel on Colab.\n", 75 | "\n", 76 | "1. Run the cell bellow (click it and press Shift+Enter),\n", 77 | "2. Change the kernel to java_use (Runtime -> Change Runtime Type -> select **\"java_use\"** -> Save)\n", 78 | "3. Try and run the following cells. The java kernel is ready if the you can load the JUnit library in the following cell. \n", 79 | "\n", 80 | "### Trouble shooting\n", 81 | " * There are two Java runtimes having similar names that you can select in step 2. If you accidentally select **java** instead of **java_use**, Colab will enter an indefinite loop, show **connecting**, and the bottom bar has a message saying \"Connecting to **java_tcp** Google Compute Engine backend\", you should delete the runtime (Runtime -> Disconnect and Delete Runtime), and run step 1 again. \n", 82 | " * The working runtime has a log message saying it is **connecting to java Google Compute Enginge Backend**" 83 | ] 84 | }, 85 | { 86 | "cell_type": "code", 87 | "execution_count": null, 88 | "id": "5b292a83", 89 | "metadata": { 90 | "id": "5b292a83", 91 | "vscode": { 92 | "languageId": "java" 93 | } 94 | }, 95 | "outputs": [], 96 | "source": [ 97 | "%%sh\n", 98 | "# Install java kernel\n", 99 | "wget -q https://github.com/SpencerPark/IJava/releases/download/v1.3.0/ijava-1.3.0.zip \n", 100 | "unzip -q ijava-1.3.0.zip \n", 101 | "python install.py\n", 102 | "\n", 103 | "# Install proxy for the java kernel\n", 104 | "wget -qO- https://gist.github.com/wenta0g/67289a9b2e54b8128109abb3aff2194b/archive/0707f5d61d156ce2830505679994b0f1a606589b.tar.gz | tar xvz --strip-components=1\n", 105 | "python install_ipc_proxy_kernel.py --kernel=java --implementation=ipc_proxy_kernel.py" 106 | ] 107 | }, 108 | { 109 | "cell_type": "code", 110 | "execution_count": null, 111 | "id": "8365ad18", 112 | "metadata": { 113 | "id": "8365ad18", 114 | "vscode": { 115 | "languageId": "java" 116 | } 117 | }, 118 | "outputs": [], 119 | "source": [ 120 | "%%loadFromPOM\n", 121 | "\n", 122 | "\n", 123 | " junit\n", 124 | " junit\n", 125 | " 4.13.2\n", 126 | "" 127 | ] 128 | }, 129 | { 130 | "cell_type": "markdown", 131 | "id": "f0bf0da4", 132 | "metadata": { 133 | "id": "f0bf0da4" 134 | }, 135 | "source": [ 136 | "The following is a basic Java implementation of `Bubble Sort`." 137 | ] 138 | }, 139 | { 140 | "cell_type": "code", 141 | "execution_count": null, 142 | "id": "e1a39dc5", 143 | "metadata": { 144 | "id": "e1a39dc5", 145 | "vscode": { 146 | "languageId": "java" 147 | } 148 | }, 149 | "outputs": [], 150 | "source": [ 151 | "public class Bubble {\n", 152 | "\n", 153 | " static final int SIZE = 10;\n", 154 | " static final int data[] = {11, 4, 8, 22, 15, 7, 8, 19, 20, 1};\n", 155 | " static int counter;\n", 156 | " static int order;\n", 157 | " \n", 158 | " public static boolean up(int A, int B) {\n", 159 | " return A < B;\n", 160 | " }\n", 161 | " \n", 162 | " public static boolean down(int A, int B) {\n", 163 | " return B < A;\n", 164 | " }\n", 165 | " \n", 166 | " public static void printArray() {\n", 167 | " for (counter = 0; counter < SIZE; counter++)\n", 168 | " System.out.print(data[counter] + \" \");\n", 169 | " System.out.println();\n", 170 | " }\n", 171 | "\n", 172 | " public static int[] bubble(int data[], int size, int order) {\n", 173 | " int pass, count;\n", 174 | " for (pass = 0; pass < SIZE - 1; pass++) {\n", 175 | " for (count = 0; count < SIZE - 1; count++) {\n", 176 | " if (order == 0) {\n", 177 | " if (up(data[count], data[count + 1])) {\n", 178 | " swap(data, count);\n", 179 | " }\n", 180 | " } else {\n", 181 | " if (down(data[count], data[count + 1])) {\n", 182 | " swap(data, count);\n", 183 | " }\n", 184 | " }\n", 185 | " }\n", 186 | " }\n", 187 | " return data;\n", 188 | " }\n", 189 | " \n", 190 | " public static void swap(int data[], int count) {\n", 191 | " int temp = data[count];\n", 192 | " data[count] = data[count+1];\n", 193 | " data[count+1] = temp;\n", 194 | " }\n", 195 | "}" 196 | ] 197 | }, 198 | { 199 | "cell_type": "code", 200 | "execution_count": null, 201 | "id": "199842ec", 202 | "metadata": { 203 | "id": "199842ec", 204 | "outputId": "ce74d455-7585-4ee9-eadd-ab4e213f9304", 205 | "scrolled": true, 206 | "vscode": { 207 | "languageId": "java" 208 | } 209 | }, 210 | "outputs": [ 211 | { 212 | "name": "stdout", 213 | "output_type": "stream", 214 | "text": [ 215 | "1 4 7 8 8 11 15 19 20 22 \n" 216 | ] 217 | } 218 | ], 219 | "source": [ 220 | "// bubble (int[] data, int size, int order), 0 for descending, and 1 for ascending\n", 221 | "Bubble.bubble(Bubble.data, 10, 1);\n", 222 | "Bubble.printArray();" 223 | ] 224 | }, 225 | { 226 | "cell_type": "code", 227 | "execution_count": null, 228 | "id": "e345c214", 229 | "metadata": { 230 | "id": "e345c214", 231 | "vscode": { 232 | "languageId": "java" 233 | } 234 | }, 235 | "outputs": [], 236 | "source": [ 237 | "import org.junit.Assert;\n", 238 | "import java.util.Arrays;\n", 239 | "import java.util.Collection;\n", 240 | "\n", 241 | "import org.junit.Test;\n", 242 | "import org.junit.runner.JUnitCore;\n", 243 | "import org.junit.runner.Result;\n", 244 | "import org.junit.runner.RunWith;\n", 245 | "import org.junit.runner.notification.Failure;\n", 246 | "import org.junit.runners.Parameterized;\n", 247 | "\n", 248 | "import junit.framework.TestCase;\n", 249 | "\n", 250 | "@RunWith(Parameterized.class)\n", 251 | "public class TestBubble extends TestCase {\n", 252 | "\n", 253 | " @Parameterized.Parameter(0)\n", 254 | " public int[] data;\n", 255 | " @Parameterized.Parameter(1)\n", 256 | " public int size;\n", 257 | " @Parameterized.Parameter(2)\n", 258 | " public int order;\n", 259 | " @Parameterized.Parameter(3)\n", 260 | " public int[] result;\n", 261 | " \n", 262 | " @Parameterized.Parameters(name = \"{index}: data: {0} size:{1} order:{2} results:{3}\")\n", 263 | " public static Collection data() {\n", 264 | " Object[][] data = new Object[][]{\n", 265 | " // Your Test cases start here\n", 266 | " {new int[]{1, 3, 2, 4, 5, 6, 7, 8, 10, 9}, 10, 1, new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}},\n", 267 | " // Your Test cases end here\n", 268 | " };\n", 269 | " return Arrays.asList(data);\n", 270 | " }\n", 271 | " \n", 272 | " @Test\n", 273 | " public void testBubble() {\n", 274 | " Assert.assertArrayEquals(result, Bubble.bubble(data, size, order));\n", 275 | " }\n", 276 | "}" 277 | ] 278 | }, 279 | { 280 | "cell_type": "code", 281 | "execution_count": null, 282 | "id": "4320cfa9", 283 | "metadata": { 284 | "id": "4320cfa9", 285 | "outputId": "8bcec4e1-13d5-4689-c060-7bbcf666dc13", 286 | "vscode": { 287 | "languageId": "java" 288 | } 289 | }, 290 | "outputs": [ 291 | { 292 | "name": "stdout", 293 | "output_type": "stream", 294 | "text": [ 295 | "Total run count: 1, Failed run count: 0\n" 296 | ] 297 | } 298 | ], 299 | "source": [ 300 | "Result result = JUnitCore.runClasses(TestBubble.class);\n", 301 | "for (Failure failure : result.getFailures()) {\n", 302 | " System.out.println(failure.toString());\n", 303 | "}\n", 304 | "System.out.println(String.format(\"Total run count: %s, Failed run count: %s\", result.getRunCount(), result.getFailureCount()));" 305 | ] 306 | }, 307 | { 308 | "cell_type": "markdown", 309 | "id": "d568505e", 310 | "metadata": { 311 | "id": "d568505e" 312 | }, 313 | "source": [ 314 | "## Your Tasks\n", 315 | "\n", 316 | "### Task 1\n", 317 | "First, make sure you understand the program (expected to be done before the tutorial).\n", 318 | "\n", 319 | "### Task 2\n", 320 | "Determine the input domains and output domains for the functions\n", 321 | "`bubble`. \n", 322 | "\n", 323 | "Next, what are the input conditions?\n", 324 | "\n", 325 | "### Task 3\n", 326 | "Perform a static data-flow analysis on `bubble`. Draw a table such as in the notes to complete this.\n", 327 | "\n", 328 | "### Task 4\n", 329 | "Roughly sketch a set of black box test cases using equivalence partitioning.\n", 330 | "\n", 331 | "### Task 5\n", 332 | "What extra information does your data-flow analysis give you that your\n", 333 | "black-box test cases do not?" 334 | ] 335 | } 336 | ], 337 | "metadata": { 338 | "colab": { 339 | "include_colab_link": true, 340 | "name": "SWEN90006_Tutorial_04.ipynb", 341 | "provenance": [] 342 | }, 343 | "kernelspec": { 344 | "display_name": "Java", 345 | "language": "java", 346 | "name": "java" 347 | }, 348 | "language_info": { 349 | "codemirror_mode": "java", 350 | "file_extension": ".jshell", 351 | "mimetype": "text/x-java-source", 352 | "name": "Java", 353 | "pygments_lexer": "java", 354 | "version": "10.0.2+13" 355 | } 356 | }, 357 | "nbformat": 4, 358 | "nbformat_minor": 5 359 | } 360 | -------------------------------------------------------------------------------- /SWEN90006_Tutorial_4_2024.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "colab_type": "text", 7 | "id": "view-in-github" 8 | }, 9 | "source": [ 10 | "\"Open" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "id": "64f8c7b9", 16 | "metadata": { 17 | "id": "64f8c7b9" 18 | }, 19 | "source": [ 20 | "# SWEN90006 Tutorial 4" 21 | ] 22 | }, 23 | { 24 | "cell_type": "markdown", 25 | "id": "5d778b91", 26 | "metadata": { 27 | "id": "5d778b91" 28 | }, 29 | "source": [ 30 | "## Introduction\n", 31 | "The purpose of this tutorial is for you to gain a deeper understanding\n", 32 | "of control- and data-flow techniques, and to compare these to input\n", 33 | "partitioning techniques." 34 | ] 35 | }, 36 | { 37 | "cell_type": "markdown", 38 | "id": "f486e92f", 39 | "metadata": { 40 | "id": "f486e92f" 41 | }, 42 | "source": [ 43 | "### Prepare the Java Kernel\n", 44 | "Since Java is not natively supported by Colab, we need to run the following code to enable Java kernel on Colab.\n", 45 | "\n", 46 | "1. Run the cell bellow (click it and press Shift+Enter),\n", 47 | "2. Change the kernel to java_use (Runtime -> Change Runtime Type -> select **\"java_use\"** -> Save)\n", 48 | "3. Try and run the following cells. The java kernel is ready if the you can load the JUnit library in the following cell. \n", 49 | "\n", 50 | "### Trouble shooting\n", 51 | " * There are two Java runtimes having similar names that you can select in step 2. If you accidentally select **java** instead of **java_use**, Colab will enter an indefinite loop, show **connecting**, and the bottom bar has a message saying \"Connecting to **java_tcp** Google Compute Engine backend\", you should delete the runtime (Runtime -> Disconnect and Delete Runtime), and run step 1 again. \n", 52 | " * The working runtime has a log message saying it is **connecting to java Google Compute Enginge Backend**" 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": null, 58 | "id": "5b292a83", 59 | "metadata": { 60 | "id": "5b292a83" 61 | }, 62 | "outputs": [], 63 | "source": [ 64 | "%%sh\n", 65 | "# Install java kernel\n", 66 | "wget -q https://github.com/SpencerPark/IJava/releases/download/v1.3.0/ijava-1.3.0.zip \n", 67 | "unzip -q ijava-1.3.0.zip \n", 68 | "python install.py\n", 69 | "\n", 70 | "# Install proxy for the java kernel\n", 71 | "wget -qO- https://gist.github.com/wenta0g/67289a9b2e54b8128109abb3aff2194b/archive/0707f5d61d156ce2830505679994b0f1a606589b.tar.gz | tar xvz --strip-components=1\n", 72 | "python install_ipc_proxy_kernel.py --kernel=java --implementation=ipc_proxy_kernel.py" 73 | ] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": 1, 78 | "id": "8365ad18", 79 | "metadata": { 80 | "id": "8365ad18" 81 | }, 82 | "outputs": [], 83 | "source": [ 84 | "%%loadFromPOM\n", 85 | "\n", 86 | "\n", 87 | " junit\n", 88 | " junit\n", 89 | " 4.13.2\n", 90 | "" 91 | ] 92 | }, 93 | { 94 | "cell_type": "markdown", 95 | "id": "89001280", 96 | "metadata": {}, 97 | "source": [ 98 | "# Part 1 Control Flow Criteria\n", 99 | "\n", 100 | "White-box testing provides more information to the tester than black box testing. One special case is when the requirements is not correctly stated to perform Equivalence Partitioning, or a simple input leads to very complex system behaviour where a short requirements is not sufficient to describe all possible expected outcomes. \n", 101 | "\n", 102 | "## Working With the Program - Control flow analysis\n", 103 | "\n", 104 | "In the first part of the tutorial, we provided a code snippet simulating image transformations done in the LibPNG library. \n", 105 | "\n", 106 | "LibPNG supports a list of image transformations when reading and writing a given image, for example, converting rgb images to gray or creating or deleting color channels. You do not need to know what these transformation means. Suppose in the LibPNG library, a 8-bit integer called `transformations` is used to represent the transformation to be performed. Four transformation will be performed. The condition to perform each condition is to check whether some part of the transformation flag is following certain patterns. For example, to perform transformation \"second\", the bit at index 1 and 2 must be set to 1. \n", 107 | "\n", 108 | "For simplisity, each transformation is controled by a unique set of bits." 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": 112, 114 | "id": "fc00a63f", 115 | "metadata": {}, 116 | "outputs": [], 117 | "source": [ 118 | "import java.util.ArrayList;\n", 119 | "import java.util.List;\n", 120 | "\n", 121 | "public class MyClass {\n", 122 | " // Fields\n", 123 | " private int myField;\n", 124 | " private List transformations = new ArrayList<>();\n", 125 | " \n", 126 | " // Constructor\n", 127 | " public MyClass(String binary) {\n", 128 | " this.myField = parseBinaryString(binary);\n", 129 | " }\n", 130 | "\n", 131 | " // reject if the binary string is not 8 bits, or it contains non-binary characters\n", 132 | " // parse the binary string to an integer\n", 133 | " public int parseBinaryString(String binary){\n", 134 | "\n", 135 | " if (binary.length() != 8 || !binary.matches(\"[01]+\")) {\n", 136 | " //System.out.println(\"Invalid binary string\");\n", 137 | " throw new IllegalArgumentException(\"must be a string of 8 chars, each char is either 0 or 1\");\n", 138 | " }\n", 139 | "\n", 140 | " int decimal = Integer.parseInt(binary, 2);\n", 141 | " return decimal;\n", 142 | "\n", 143 | " }\n", 144 | " // Check if the n-th bit is 1\n", 145 | " public boolean isSet(int n) {\n", 146 | " return (myField & (1 << n)) != 0;\n", 147 | " }\n", 148 | "\n", 149 | " // Print the list of transformation to be performed\n", 150 | " public void PNG_initialize_transformation() {\n", 151 | " // Add more transformations as needed\n", 152 | "\n", 153 | " // The first transformation is set when the 0th bit is set\n", 154 | " if (isSet(0)) {\n", 155 | " transformations.add(\"First\");\n", 156 | " }\n", 157 | " // The second transformation is set when both the 1st and 2nd bits are set \n", 158 | " if (isSet(1) && isSet(2)) {\n", 159 | " transformations.add(\"Second\");\n", 160 | " }\n", 161 | "\n", 162 | " // The third transformation is set when the 3rd bit is set and either the 4th or 5th bit is set\n", 163 | " if (isSet(3) && (isSet(4) || isSet(5))) {\n", 164 | " transformations.add(\"Third\");\n", 165 | " }\n", 166 | "\n", 167 | " // The fourth transformation is set when the 6th bit is not set or the 7th bit is set\n", 168 | " if (!isSet(6) || isSet(7)) {\n", 169 | " transformations.add(\"Fourth\");\n", 170 | " }\n", 171 | " }\n", 172 | " // Print out the list of transformations to be performed\n", 173 | " public void printTransformations() {\n", 174 | " System.out.println(\"Transformations to perform: \" + transformations);\n", 175 | " }\n", 176 | "}\n" 177 | ] 178 | }, 179 | { 180 | "cell_type": "code", 181 | "execution_count": 114, 182 | "id": "b1f8551a", 183 | "metadata": {}, 184 | "outputs": [ 185 | { 186 | "name": "stdout", 187 | "output_type": "stream", 188 | "text": [ 189 | "Transformations to perform: [Second, Fourth]\n" 190 | ] 191 | } 192 | ], 193 | "source": [ 194 | "// Please provide a string having at most 8 characters, and only 0s and 1s\n", 195 | "// Other input will be rejected\n", 196 | "String binary = \"00010110\"; \n", 197 | "\n", 198 | "MyClass myclass = new MyClass(binary);\n", 199 | "\n", 200 | "// check which transformations to perform due to some combinations of flags\n", 201 | "myclass.PNG_initialize_transformation();\n", 202 | "\n", 203 | "// print out the transformations to be performed\n", 204 | "myclass.printTransformations();\n" 205 | ] 206 | }, 207 | { 208 | "cell_type": "markdown", 209 | "id": "4b814bea", 210 | "metadata": {}, 211 | "source": [ 212 | "## Your Task\n", 213 | "\n", 214 | "We will work on the different coverage criteria, looking at the `PNG_initialize_transformation` function. The control flow graph of the `PNG_initialize_transformation` function is attached for your reference. \n", 215 | "\n", 216 | "\n", 217 | "\n", 218 | "### Task 1: \n", 219 | "\n", 220 | " For the given set of test cases, calculate the `branch coverage` score, using the given template (You only need to fill in blanks in the table and the coverage score). If your set of test cases does not achieve 100% `branch coverage`, add some test cases that achieves `branch coverage`. \n", 221 | "\n", 222 | "**Hint:** is making a branch `true` equivalent to performing the corresponding transformation? \n", 223 | "\n", 224 | "\n", 225 | "Set of test cases:\n", 226 | "- `binary = \"00000111\"`\n", 227 | "- `binary = \"10101010\"`\n", 228 | "- `binary = \"11110000\"`\n", 229 | "\n", 230 | "| Branch | Branch 1 | Branch 1 | Branch 2 | Branch 2 | Branch 3 | Branch 3 | Branch 4 | Branch 4 |\n", 231 | "|-----------------|----------|-----------|----------|----------|----------|----------|----------|----------|\n", 232 | "| Test objectives | True | False | True | False | True | False | True | False |\n", 233 | "| 00000111 | | | | | | | | |\n", 234 | "| 10101010 | | | | | | | | |\n", 235 | "| 11110000 | | | | | | | | |\n", 236 | " \n", 237 | "$coverage\\_score = \\frac{objectives\\_achieved}{total\\_objectives} $\n", 238 | "\n", 239 | "\n", 240 | "### Task 2:\n", 241 | "\n", 242 | "Design a set of test cases that achieves `condition coverage`. \n", 243 | "\n", 244 | "Note: we do not consider code optimizations during compilations. The implication is that for a branch like `if (a and b)`, an optimized code may not check `b` given `a` is false. But we will **always check whether `a` and `b` is True or False**. \n", 245 | "\n", 246 | "\n", 247 | "### Task 3:\n", 248 | "\n", 249 | "Design a set of test cases that achieves `decision/condition coverage`.\n" 250 | ] 251 | }, 252 | { 253 | "cell_type": "markdown", 254 | "id": "f472fc3d", 255 | "metadata": {}, 256 | "source": [ 257 | "## Part 2 Dataflow Analysis" 258 | ] 259 | }, 260 | { 261 | "cell_type": "markdown", 262 | "id": "78f1bb8a", 263 | "metadata": { 264 | "id": "78f1bb8a" 265 | }, 266 | "source": [ 267 | "## Working With the Program\n", 268 | "\n", 269 | "In this tutorial we will focus on the procedure `bubble`, found in\n", 270 | "Figure 1. The program below serves to show you how we\n", 271 | "intend to use `bubble`. Of course, `bubble` implements a bubble sort.\n", 272 | "\n", 273 | "Make special note of the third parameter to `bubble`, called `order`. This parameter allows us to create a flexible sorting algorithm, which can be used to sort in either ascending or descending order. Both functions `up` and `down` take two integers and return an integer (which is intended to be a boolean value). For this tutorial consider\n", 274 | "just\n", 275 | "\n", 276 | "```java\n", 277 | "public static boolean up(int A, int B) {\n", 278 | " return A < B;\n", 279 | "}\n", 280 | "```\n", 281 | "\n", 282 | "and\n", 283 | "\n", 284 | "```java\n", 285 | "public static boolean down(int A, int B) {\n", 286 | " return B < A;\n", 287 | "}\n", 288 | "```" 289 | ] 290 | }, 291 | { 292 | "cell_type": "markdown", 293 | "id": "f0bf0da4", 294 | "metadata": { 295 | "id": "f0bf0da4" 296 | }, 297 | "source": [ 298 | "The following is a basic Java implementation of `Bubble Sort`." 299 | ] 300 | }, 301 | { 302 | "cell_type": "code", 303 | "execution_count": 25, 304 | "id": "e1a39dc5", 305 | "metadata": { 306 | "id": "e1a39dc5" 307 | }, 308 | "outputs": [], 309 | "source": [ 310 | "public class Bubble {\n", 311 | "\n", 312 | " static final int SIZE = 10;\n", 313 | " static final int data[] = {11, 4, 8, 22, 15, 7, 8, 19, 20, 1};\n", 314 | " static int counter;\n", 315 | " static int order;\n", 316 | " \n", 317 | " public static boolean up(int A, int B) {\n", 318 | " return A < B;\n", 319 | " }\n", 320 | " \n", 321 | " public static boolean down(int A, int B) {\n", 322 | " return B < A;\n", 323 | " }\n", 324 | " \n", 325 | " public static void printArray() {\n", 326 | " for (counter = 0; counter < SIZE; counter++)\n", 327 | " System.out.print(data[counter] + \" \");\n", 328 | " System.out.println();\n", 329 | " }\n", 330 | "\n", 331 | " public static int[] bubble(int data[], int size, int order) {\n", 332 | " int pass, count;\n", 333 | " for (pass = 0; pass < SIZE - 1; pass++) {\n", 334 | " for (count = 0; count < SIZE - 1; count++) {\n", 335 | " if (order == 0) {\n", 336 | " if (up(data[count], data[count + 1])) {\n", 337 | " swap(data, count);\n", 338 | " }\n", 339 | " } else {\n", 340 | " if (down(data[count], data[count + 1])) {\n", 341 | " swap(data, count);\n", 342 | " }\n", 343 | " }\n", 344 | " }\n", 345 | " }\n", 346 | " return data;\n", 347 | " }\n", 348 | " \n", 349 | " public static void swap(int data[], int count) {\n", 350 | " int temp = data[count];\n", 351 | " data[count] = data[count+1];\n", 352 | " data[count+1] = temp;\n", 353 | " }\n", 354 | "}" 355 | ] 356 | }, 357 | { 358 | "cell_type": "code", 359 | "execution_count": 27, 360 | "id": "199842ec", 361 | "metadata": { 362 | "id": "199842ec", 363 | "outputId": "ce74d455-7585-4ee9-eadd-ab4e213f9304", 364 | "scrolled": true 365 | }, 366 | "outputs": [ 367 | { 368 | "name": "stdout", 369 | "output_type": "stream", 370 | "text": [ 371 | "1 4 7 8 8 11 15 19 20 22 \n" 372 | ] 373 | } 374 | ], 375 | "source": [ 376 | "// bubble (int[] data, int size, int order), 0 for descending, and 1 for ascending\n", 377 | "Bubble.bubble(Bubble.data, 10, 1);\n", 378 | "Bubble.printArray();" 379 | ] 380 | }, 381 | { 382 | "cell_type": "code", 383 | "execution_count": 9, 384 | "id": "e345c214", 385 | "metadata": { 386 | "id": "e345c214" 387 | }, 388 | "outputs": [], 389 | "source": [ 390 | "import org.junit.Assert;\n", 391 | "import java.util.Arrays;\n", 392 | "import java.util.Collection;\n", 393 | "\n", 394 | "import org.junit.Test;\n", 395 | "import org.junit.runner.JUnitCore;\n", 396 | "import org.junit.runner.Result;\n", 397 | "import org.junit.runner.RunWith;\n", 398 | "import org.junit.runner.notification.Failure;\n", 399 | "import org.junit.runners.Parameterized;\n", 400 | "\n", 401 | "import junit.framework.TestCase;\n", 402 | "\n", 403 | "@RunWith(Parameterized.class)\n", 404 | "public class TestBubble extends TestCase {\n", 405 | "\n", 406 | " @Parameterized.Parameter(0)\n", 407 | " public int[] data;\n", 408 | " @Parameterized.Parameter(1)\n", 409 | " public int size;\n", 410 | " @Parameterized.Parameter(2)\n", 411 | " public int order;\n", 412 | " @Parameterized.Parameter(3)\n", 413 | " public int[] result;\n", 414 | " \n", 415 | " @Parameterized.Parameters(name = \"{index}: data: {0} size:{1} order:{2} results:{3}\")\n", 416 | " public static Collection data() {\n", 417 | " Object[][] data = new Object[][]{\n", 418 | " // Your Test cases start here\n", 419 | " {new int[]{1, 3, 2, 4, 5, 6, 7, 8, 10, 9}, 10, 1, new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}},\n", 420 | " // Your Test cases end here\n", 421 | " };\n", 422 | " return Arrays.asList(data);\n", 423 | " }\n", 424 | " \n", 425 | " @Test\n", 426 | " public void testBubble() {\n", 427 | " Assert.assertArrayEquals(result, Bubble.bubble(data, size, order));\n", 428 | " }\n", 429 | "}" 430 | ] 431 | }, 432 | { 433 | "cell_type": "code", 434 | "execution_count": 10, 435 | "id": "4320cfa9", 436 | "metadata": { 437 | "id": "4320cfa9", 438 | "outputId": "8bcec4e1-13d5-4689-c060-7bbcf666dc13" 439 | }, 440 | "outputs": [ 441 | { 442 | "name": "stdout", 443 | "output_type": "stream", 444 | "text": [ 445 | "testBubble[0: data: [I@1c2d6001 size:10 order:1 results:[I@6dd60873](REPL.$JShell$28D$TestBubble): arrays first differed at element [8]; expected:<9> but was:<22>\n", 446 | "Total run count: 1, Failed run count: 1\n" 447 | ] 448 | } 449 | ], 450 | "source": [ 451 | "Result result = JUnitCore.runClasses(TestBubble.class);\n", 452 | "for (Failure failure : result.getFailures()) {\n", 453 | " System.out.println(failure.toString());\n", 454 | "}\n", 455 | "System.out.println(String.format(\"Total run count: %s, Failed run count: %s\", result.getRunCount(), result.getFailureCount()));" 456 | ] 457 | }, 458 | { 459 | "cell_type": "markdown", 460 | "id": "d568505e", 461 | "metadata": { 462 | "id": "d568505e" 463 | }, 464 | "source": [ 465 | "## Your Tasks\n", 466 | "\n", 467 | "### Task 1\n", 468 | "First, make sure you understand the program (expected to be done before the tutorial).\n", 469 | "\n", 470 | "### Task 2\n", 471 | "Perform a static data-flow analysis on `bubble`. Draw a table such as in the notes to complete this.\n", 472 | "\n", 473 | "### Task 3\n", 474 | "Imagine you are also performing an equivalence partitioning test. What extra information does your data-flow analysis give you that your\n", 475 | "black-box test cases do not?" 476 | ] 477 | } 478 | ], 479 | "metadata": { 480 | "colab": { 481 | "include_colab_link": true, 482 | "name": "SWEN90006_Tutorial_04.ipynb", 483 | "provenance": [] 484 | }, 485 | "kernelspec": { 486 | "display_name": "Java", 487 | "language": "java", 488 | "name": "java" 489 | }, 490 | "language_info": { 491 | "codemirror_mode": "java", 492 | "file_extension": ".jshell", 493 | "mimetype": "text/x-java-source", 494 | "name": "java", 495 | "pygments_lexer": "java", 496 | "version": "11.0.15.1+2-LTS-10" 497 | } 498 | }, 499 | "nbformat": 4, 500 | "nbformat_minor": 5 501 | } 502 | -------------------------------------------------------------------------------- /SWEN90006_Tutorial_5.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "colab_type": "text", 7 | "id": "view-in-github" 8 | }, 9 | "source": [ 10 | "\"Open" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "id": "201d404e", 16 | "metadata": { 17 | "id": "201d404e" 18 | }, 19 | "source": [ 20 | "# SWEN90006 Tutorial 5" 21 | ] 22 | }, 23 | { 24 | "cell_type": "markdown", 25 | "id": "df9e08b4", 26 | "metadata": { 27 | "id": "df9e08b4" 28 | }, 29 | "source": [ 30 | "## Introduction\n", 31 | "Encapsulation is an abstraction mechanism that aids in programming, but\n", 32 | "that adds complexity to testing. We often need to break the information\n", 33 | "hiding utilised by classes in order to examine the class state for the\n", 34 | "testing purposes.\n", 35 | "\n", 36 | "The aim of this tutorial is for you to explore some of the issues in\n", 37 | "object oriented testing through the simple Graph given below. The graph\n", 38 | "uses an adjacency matrix that records which vertices are \"*adjacent*\" in\n", 39 | "the graph." 40 | ] 41 | }, 42 | { 43 | "cell_type": "markdown", 44 | "id": "529aa40e", 45 | "metadata": { 46 | "id": "529aa40e" 47 | }, 48 | "source": [ 49 | "## Working With the Program\n", 50 | "\n", 51 | "### Prepare the Java Kernel\n", 52 | "Since Java is not natively supported by Colab, we need to run the following code to enable Java kernel on Colab.\n", 53 | "\n", 54 | "1. Run the cell bellow (click it and press Shift+Enter),\n", 55 | "2. Change the kernel to java_use (Runtime -> Change Runtime Type -> select **\"java_use\"** -> Save)\n", 56 | "3. Try and run the following cells. The java kernel is ready if the you can load the JUnit library in the following cell. \n", 57 | "\n", 58 | "### Trouble shooting\n", 59 | " * There are two Java runtimes having similar names that you can select in step 2. If you accidentally select **java** instead of **java_use**, Colab will enter an indefinite loop, show **connecting**, and the bottom bar has a message saying \"Connecting to **java_tcp** Google Compute Engine backend\", you should delete the runtime (Runtime -> Disconnect and Delete Runtime), and run step 1 again. \n", 60 | " * The working runtime has a log message saying it is **connecting to java Google Compute Enginge Backend**" 61 | ] 62 | }, 63 | { 64 | "cell_type": "code", 65 | "execution_count": null, 66 | "id": "fd4f34a4", 67 | "metadata": { 68 | "id": "fd4f34a4", 69 | "vscode": { 70 | "languageId": "java" 71 | } 72 | }, 73 | "outputs": [], 74 | "source": [ 75 | "%%sh\n", 76 | "# Install java kernel\n", 77 | "wget -q https://github.com/SpencerPark/IJava/releases/download/v1.3.0/ijava-1.3.0.zip \n", 78 | "unzip -q ijava-1.3.0.zip \n", 79 | "python install.py\n", 80 | "\n", 81 | "# Install proxy for the java kernel\n", 82 | "wget -qO- https://gist.github.com/wenta0g/67289a9b2e54b8128109abb3aff2194b/archive/0707f5d61d156ce2830505679994b0f1a606589b.tar.gz | tar xvz --strip-components=1\n", 83 | "python install_ipc_proxy_kernel.py --kernel=java --implementation=ipc_proxy_kernel.py" 84 | ] 85 | }, 86 | { 87 | "cell_type": "code", 88 | "execution_count": null, 89 | "id": "0d664ffa", 90 | "metadata": { 91 | "id": "0d664ffa", 92 | "vscode": { 93 | "languageId": "java" 94 | } 95 | }, 96 | "outputs": [], 97 | "source": [ 98 | "%%loadFromPOM\n", 99 | "\n", 100 | "\n", 101 | " junit\n", 102 | " junit\n", 103 | " 4.13.2\n", 104 | "" 105 | ] 106 | }, 107 | { 108 | "cell_type": "markdown", 109 | "id": "708b64cb", 110 | "metadata": { 111 | "id": "708b64cb" 112 | }, 113 | "source": [ 114 | "The following is a basic Java implementation of `Graph`." 115 | ] 116 | }, 117 | { 118 | "cell_type": "code", 119 | "execution_count": null, 120 | "id": "cb8f6f52", 121 | "metadata": { 122 | "id": "cb8f6f52", 123 | "vscode": { 124 | "languageId": "java" 125 | } 126 | }, 127 | "outputs": [], 128 | "source": [ 129 | "import java.util.*;\n", 130 | "\n", 131 | "public class Graph {\n", 132 | " \n", 133 | " //------------ Private Attributes ----------------------------\n", 134 | " // The representation of a graph consists of an array\n", 135 | " // of vertices that map nodes (just integers) to array \n", 136 | " // indexes. The adjacency matrix _matrix sets matrix[i][j]\n", 137 | " // to true if there is an edge between _vertices[i] and \n", 138 | " // _vertices[j].\n", 139 | " // \n", 140 | " // The operations must maintain the following invariant:\n", 141 | " // _vertices[i] is defined iff i < _allocated\n", 142 | " // _allocated <= _order\n", 143 | " static final String EMPTY_GRAPH = \"Empty Graph\";\n", 144 | " \n", 145 | " private int _order; // The number of vertices allowed \n", 146 | " private int _allocated; // The next free space in the vertex array\n", 147 | " private int _vertices[]; // A list of the actual vertices\n", 148 | " private boolean _matrix[][]; // The adjacency matrix\n", 149 | " \n", 150 | " public Graph(int n) {\n", 151 | " // Create a matrix of size n and initial all of the \n", 152 | " // state variables so that the invariant is maintained.\n", 153 | " _order = n;\n", 154 | " _allocated = 0;\n", 155 | " _vertices = _vertices(n);\n", 156 | " _matrix = _allocate(n);\n", 157 | " }\n", 158 | " \n", 159 | " public Graph(int n, int allocated, int[] vertices, boolean matrix[][]) {\n", 160 | " _order = n;\n", 161 | " _allocated = allocated;\n", 162 | " _vertices = vertices;\n", 163 | " _matrix = matrix;\n", 164 | " }\n", 165 | " \n", 166 | " private static boolean[][] _allocate(int n) {\n", 167 | " return new boolean[n][n];\n", 168 | " }\n", 169 | " \n", 170 | " private static int[] _vertices(int n) {\n", 171 | " return new int[n];\n", 172 | " }\n", 173 | " \n", 174 | " private int _lookup(int m) {\n", 175 | " int index = 0;\n", 176 | " while (index < _allocated && _vertices[index] != m) {\n", 177 | " index = index + 1;\n", 178 | " }\n", 179 | "\n", 180 | " if (index == _allocated) {\n", 181 | " return _order + 1;\n", 182 | " }\n", 183 | " else {\n", 184 | " return index;\n", 185 | " }\n", 186 | " }\n", 187 | " \n", 188 | " public void addVertex(int v) {\n", 189 | " // Add a vertex to the vertex graph. For the moment we\n", 190 | " // assume that vertices are just integers.\n", 191 | " if (_allocated < _order) {\n", 192 | " _vertices[_allocated] = v;\n", 193 | " _allocated = _allocated + 1;\n", 194 | " }\n", 195 | " }\n", 196 | " \n", 197 | " public void addEdge(int m, int n) {\n", 198 | " // Add an edge to the graph. Edges are specified by pairs\n", 199 | " // of vertices. To add the edge correctly it is necessary\n", 200 | " // that m and n have already been added to graph as vertices.\n", 201 | "\n", 202 | " int mIndex = _lookup(m);\n", 203 | " int nIndex = _lookup(n);\n", 204 | "\n", 205 | " if (mIndex < _order && nIndex < _order) {\n", 206 | " _matrix[mIndex][nIndex] = true;\n", 207 | " _matrix[nIndex][mIndex] = true;\n", 208 | " }\n", 209 | " }\n", 210 | " \n", 211 | " public void deleteVertex(int v) {\n", 212 | " // We can only delete a node if it is not part of some edge\n", 213 | " // in the graph and it exists as an actual vertex in the \n", 214 | " // graph.\n", 215 | " \n", 216 | " int vIndex = _lookup(v);\n", 217 | " \n", 218 | " if (vIndex < _order) {\n", 219 | " boolean isEdge = false; \n", 220 | " for (int i = 0; i < _allocated; i++) {\n", 221 | " isEdge = isEdge || _matrix[vIndex][i] || _matrix[i][vIndex];\n", 222 | " }\n", 223 | " \n", 224 | " if (!isEdge) {\n", 225 | " for (int i = vIndex; i < _allocated-1; i++) {\n", 226 | " _vertices[i] = _vertices[i+1];\n", 227 | " }\n", 228 | " }\n", 229 | " _allocated = _allocated - 1;\n", 230 | " }\n", 231 | " }\n", 232 | " \n", 233 | " public void deleteEdge(int m, int n) {\n", 234 | " // We can only delete an edge if the two specified\n", 235 | " // vertices are in the graph.\n", 236 | " \n", 237 | " int mIndex = _lookup(m);\n", 238 | " int nIndex = _lookup(n);\n", 239 | " \n", 240 | " if (mIndex < _order && nIndex < _order) \n", 241 | " _matrix[mIndex][nIndex] = false;\n", 242 | " }\n", 243 | " \n", 244 | " // Overrides ToString()\n", 245 | " public String toString() {\n", 246 | " StringBuilder s = new StringBuilder();\n", 247 | " if (_allocated == 0)\n", 248 | " {\n", 249 | " return EMPTY_GRAPH;\n", 250 | " }\n", 251 | " else {\n", 252 | " s.append(\"\\n \");\n", 253 | " for (int i = 0; i < _allocated; i++)\n", 254 | " {\n", 255 | " s.append(i + \" \");\n", 256 | " }\n", 257 | " s.append(\"\\n\");\n", 258 | " for (int i = 0; i < _allocated; i++) {\n", 259 | " s.append(i + \": \");\n", 260 | " for (boolean j : _matrix[i]) {\n", 261 | " s.append((j ? \"T\" : \" \") + \" \");\n", 262 | " }\n", 263 | " s.append(\"\\n\");\n", 264 | " }\n", 265 | " return s.toString();\n", 266 | " }\n", 267 | " }\n", 268 | "}" 269 | ] 270 | }, 271 | { 272 | "cell_type": "markdown", 273 | "id": "eab02640", 274 | "metadata": { 275 | "id": "eab02640" 276 | }, 277 | "source": [ 278 | "The code block below demostrates how to create graph" 279 | ] 280 | }, 281 | { 282 | "cell_type": "code", 283 | "execution_count": null, 284 | "id": "0e05e61f", 285 | "metadata": { 286 | "id": "0e05e61f", 287 | "outputId": "ce74d455-7585-4ee9-eadd-ab4e213f9304", 288 | "scrolled": false, 289 | "vscode": { 290 | "languageId": "java" 291 | } 292 | }, 293 | "outputs": [ 294 | { 295 | "name": "stdout", 296 | "output_type": "stream", 297 | "text": [ 298 | "\n", 299 | " 0 1 2 3 4 5 \n", 300 | "0: \n", 301 | "1: T \n", 302 | "2: \n", 303 | "3: T \n", 304 | "4: \n", 305 | "5: \n", 306 | "\n", 307 | "Empty Graph\n", 308 | "\n", 309 | "\n", 310 | " 0 1 2 3 \n", 311 | "0: \n", 312 | "1: \n", 313 | "2: \n", 314 | "3: \n", 315 | "\n", 316 | "\n", 317 | " 0 1 2 3 4 5 \n", 318 | "0: \n", 319 | "1: T \n", 320 | "2: \n", 321 | "3: T \n", 322 | "4: \n", 323 | "5: \n", 324 | "\n", 325 | "true\n" 326 | ] 327 | } 328 | ], 329 | "source": [ 330 | "// Method 1: pass all params into the constructor\n", 331 | "// Pre-define a matrix\n", 332 | "boolean[][] matrix = new boolean[6][6];\n", 333 | "for (int i = 0; i < matrix.length ; i++) {\n", 334 | " Arrays.fill(matrix [i], false);\n", 335 | "}\n", 336 | "\n", 337 | "matrix[1][3] = true;\n", 338 | "matrix[3][1] = true;\n", 339 | "\n", 340 | "// Graph(int n, int allocated, int[] vertices, boolean matrix[][])\n", 341 | "// int n: The number of vertices allowed \n", 342 | "// int allocated: The next free space in the vertex array\n", 343 | "// int[] verties: A list of the actual vertices\n", 344 | "// boolean matrix[][]: The adjacency matrix\n", 345 | "Graph graph_1 = new Graph(6, 6, new int[] {0, 1, 2, 3, 4, 5}, matrix);\n", 346 | "\n", 347 | "// Print the Graph\n", 348 | "System.out.println(graph_1);\n", 349 | "\n", 350 | "// Method 2:\n", 351 | "Graph graph_2 = new Graph(6);\n", 352 | "System.out.println(graph_2);\n", 353 | "System.out.println();\n", 354 | "// Add Vertex\n", 355 | "graph_2.addVertex(0);\n", 356 | "graph_2.addVertex(1);\n", 357 | "graph_2.addVertex(2);\n", 358 | "graph_2.addVertex(3);\n", 359 | "System.out.println(graph_2);\n", 360 | "graph_2.addVertex(4);\n", 361 | "graph_2.addVertex(5);\n", 362 | "\n", 363 | "// Add Edge\n", 364 | "graph_2.addEdge(1, 3);\n", 365 | "\n", 366 | "// Print the Graph\n", 367 | "System.out.println(graph_2);\n", 368 | "\n", 369 | "// Check if they are identical or not\n", 370 | "// In this case, it should be true\n", 371 | "System.out.println(graph_1.toString().equals(graph_2.toString()))" 372 | ] 373 | }, 374 | { 375 | "cell_type": "code", 376 | "execution_count": null, 377 | "id": "56608cbf", 378 | "metadata": { 379 | "id": "56608cbf", 380 | "vscode": { 381 | "languageId": "java" 382 | } 383 | }, 384 | "outputs": [], 385 | "source": [ 386 | "import java.util.Arrays;\n", 387 | "import java.util.Collection;\n", 388 | "\n", 389 | "import org.junit.Test;\n", 390 | "import org.junit.runner.JUnitCore;\n", 391 | "import org.junit.runner.Result;\n", 392 | "import org.junit.runner.RunWith;\n", 393 | "import org.junit.runner.notification.Failure;\n", 394 | "import org.junit.runners.Parameterized;\n", 395 | "\n", 396 | "import junit.framework.TestCase;\n", 397 | "\n", 398 | "@RunWith(Parameterized.class)\n", 399 | "public class TestGraph extends TestCase {\n", 400 | " @Parameterized.Parameter(0)\n", 401 | " public String actual;\n", 402 | " @Parameterized.Parameter(1)\n", 403 | " public String expected;\n", 404 | " \n", 405 | " @Parameterized.Parameters(name = \"{index}:\\ngraph 1: \\n{0}\\ngraph 2:\\n{1}\\n\")\n", 406 | " public static Collection data() {\n", 407 | "\n", 408 | " // Define your params and constructor here\n", 409 | " boolean[][] matrix = new boolean[6][6];\n", 410 | " for (int i = 0; i < matrix.length ; i++) {\n", 411 | " Arrays.fill(matrix [i], false);\n", 412 | " }\n", 413 | " \n", 414 | " matrix[1][3] = true;\n", 415 | " matrix[3][1] = true;\n", 416 | " \n", 417 | " Graph expectedGraph = new Graph(6, 6, new int[]{0, 1, 2, 3, 4, 5}, matrix);\n", 418 | "\n", 419 | " Graph actualGraph = new Graph(6);\n", 420 | " actualGraph.addVertex(0);\n", 421 | " actualGraph.addVertex(1);\n", 422 | " actualGraph.addVertex(2);\n", 423 | " actualGraph.addVertex(3);\n", 424 | " actualGraph.addVertex(4);\n", 425 | " actualGraph.addVertex(5);\n", 426 | " actualGraph.addEdge(1, 3);\n", 427 | " \n", 428 | " Graph emptyGraph = new Graph(6);\n", 429 | " // End of pre-define\n", 430 | " \n", 431 | " \n", 432 | " Object[][] data = new Object[][]{\n", 433 | " // Your Test cases start here\n", 434 | " // Please follow the pattern: expected graph, actual graph\n", 435 | "\n", 436 | " // Success\n", 437 | " {expectedGraph.toString(), actualGraph.toString()},\n", 438 | " // Success\n", 439 | " {Graph.EMPTY_GRAPH, emptyGraph.toString()},\n", 440 | " // Fail\n", 441 | " {Graph.EMPTY_GRAPH, actualGraph.toString()}\n", 442 | " // Your Test cases end here\n", 443 | " };\n", 444 | " return Arrays.asList(data);\n", 445 | " }\n", 446 | " \n", 447 | " @Test\n", 448 | " public void testGraph() {\n", 449 | " assertEquals(expected, actual);\n", 450 | " }\n", 451 | "}" 452 | ] 453 | }, 454 | { 455 | "cell_type": "code", 456 | "execution_count": null, 457 | "id": "c0416df8", 458 | "metadata": { 459 | "id": "c0416df8", 460 | "outputId": "48e9a17a-a347-4873-d309-f74dbb8846bb", 461 | "vscode": { 462 | "languageId": "java" 463 | } 464 | }, 465 | "outputs": [ 466 | { 467 | "name": "stdout", 468 | "output_type": "stream", 469 | "text": [ 470 | "testGraph[2:\n", 471 | "graph 1: \n", 472 | "Empty Graph\n", 473 | "graph 2:\n", 474 | "\n", 475 | " 0 1 2 3 4 5 \n", 476 | "0: \n", 477 | "1: T \n", 478 | "2: \n", 479 | "3: T \n", 480 | "4: \n", 481 | "5: \n", 482 | "\n", 483 | "](REPL.$JShell$44H$TestGraph): expected:<[\n", 484 | " 0 1 2 3 4 5 \n", 485 | "0: \n", 486 | "1: T \n", 487 | "2: \n", 488 | "3: T \n", 489 | "4: \n", 490 | "5: \n", 491 | "]> but was:<[Empty Graph]>\n", 492 | "Total run count: 3, Failed run count: 1\n" 493 | ] 494 | } 495 | ], 496 | "source": [ 497 | "Result result = JUnitCore.runClasses(TestGraph.class);\n", 498 | "for (Failure failure : result.getFailures()) {\n", 499 | " System.out.println(failure.toString());\n", 500 | "}\n", 501 | "System.out.println(String.format(\"Total run count: %s, Failed run count: %s\", result.getRunCount(), result.getFailureCount()));" 502 | ] 503 | }, 504 | { 505 | "cell_type": "markdown", 506 | "id": "fe84671f", 507 | "metadata": { 508 | "id": "fe84671f" 509 | }, 510 | "source": [ 511 | "## Your Tasks\n", 512 | "\n", 513 | "### Task 1\n", 514 | "Consider the `addEdge` and `deleteEdge` methods in the `Graph` class\n", 515 | "above. Derive test cases for path coverage and condition coverage for\n", 516 | "these two methods. **Note** that it may be necessary to examine the\n", 517 | "state variables in your test cases. Sketch how you would achieve this.\n", 518 | "\n", 519 | "### Task 2\n", 520 | "Given that a Graph object has already been initialized with the number K, draw a finite state automaton for this `Graph` object. **Note** that it is not\n", 521 | "always possible to add an edge and it is not always possible to delete a\n", 522 | "vertex. You will need to consider the states and the guards on\n", 523 | "transitions to ensure all of the conditions.\n", 524 | "\n", 525 | "### Task 3\n", 526 | "Derive a set of test cases to test every transition in your graph.\n", 527 | "\n" 528 | ] 529 | } 530 | ], 531 | "metadata": { 532 | "colab": { 533 | "include_colab_link": true, 534 | "name": "SWEN90006_Tutorial_05.ipynb", 535 | "provenance": [] 536 | }, 537 | "kernelspec": { 538 | "display_name": "Java", 539 | "language": "java", 540 | "name": "java" 541 | }, 542 | "language_info": { 543 | "codemirror_mode": "java", 544 | "file_extension": ".jshell", 545 | "mimetype": "text/x-java-source", 546 | "name": "Java", 547 | "pygments_lexer": "java", 548 | "version": "10.0.2+13" 549 | } 550 | }, 551 | "nbformat": 4, 552 | "nbformat_minor": 5 553 | } 554 | -------------------------------------------------------------------------------- /SWEN90006_Tutorial_6.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "colab_type": "text", 7 | "id": "view-in-github" 8 | }, 9 | "source": [ 10 | "\"Open" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "id": "9f6077ed", 16 | "metadata": { 17 | "id": "9f6077ed" 18 | }, 19 | "source": [ 20 | "# SWEN90006 Tutorial 6" 21 | ] 22 | }, 23 | { 24 | "cell_type": "markdown", 25 | "id": "97e7daf0", 26 | "metadata": { 27 | "id": "97e7daf0" 28 | }, 29 | "source": [ 30 | "## Introduction\n", 31 | "The aim of this tutorial is for you to familiarise yourself with the\n", 32 | "test oracles and random testing. This tutorial will help to gain an\n", 33 | "understanding of how to specify a test oracle to decide whether an\n", 34 | "arbitrary test case is correct, incorrect or undecidable, as well as how\n", 35 | "to randomly generate test cases that fit an operational profile." 36 | ] 37 | }, 38 | { 39 | "cell_type": "markdown", 40 | "id": "46680c7b", 41 | "metadata": { 42 | "id": "46680c7b" 43 | }, 44 | "source": [ 45 | "## Working With the Program\n", 46 | "\n", 47 | "### First Program\n", 48 | "\n", 49 | "We shall start this tutorial by using a rather simple example to\n", 50 | "illustrate the concepts, techniques and issues faced when working with\n", 51 | "oracles. This is followed by applying these techniques to the root\n", 52 | "finding program from tutorial 4 to gain some practice with practical\n", 53 | "examples.\n", 54 | "\n", 55 | "This *toLower* is an application which takes a string on standard input\n", 56 | "and puts a corresponding string on standard output, with all upper case\n", 57 | "letters changed to the matching lower case letters (i.e. 'A' to 'a', 'B'\n", 58 | "to 'b', etc.). Strings may consist of all ASCII characters between 32\n", 59 | "and 126 inclusive; characters outside this range are control characters\n", 60 | "and will cause an error message.\n", 61 | "\n", 62 | "### Prepare the Java Kernel\n", 63 | "Since Java is not natively supported by Colab, we need to run the following code to enable Java kernel on Colab.\n", 64 | "\n", 65 | "1. Run the cell bellow (click it and press Shift+Enter),\n", 66 | "2. Change the kernel to java_use (Runtime -> Change Runtime Type -> select **\"java_use\"** -> Save)\n", 67 | "3. Try and run the following cells. The java kernel is ready if the you can load the JUnit library in the following cell. \n", 68 | "\n", 69 | "### Trouble shooting\n", 70 | " * There are two Java runtimes having similar names that you can select in step 2. If you accidentally select **java** instead of **java_use**, Colab will enter an indefinite loop, show **connecting**, and the bottom bar has a message saying \"Connecting to **java_tcp** Google Compute Engine backend\", you should delete the runtime (Runtime -> Disconnect and Delete Runtime), and run step 1 again. \n", 71 | " * The working runtime has a log message saying it is **connecting to java Google Compute Enginge Backend**" 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": null, 77 | "id": "fe971ad0", 78 | "metadata": { 79 | "id": "fe971ad0", 80 | "vscode": { 81 | "languageId": "java" 82 | } 83 | }, 84 | "outputs": [], 85 | "source": [ 86 | "%%sh\n", 87 | "# Install java kernel\n", 88 | "wget -q https://github.com/SpencerPark/IJava/releases/download/v1.3.0/ijava-1.3.0.zip \n", 89 | "unzip -q ijava-1.3.0.zip \n", 90 | "python install.py\n", 91 | "\n", 92 | "# Install proxy for the java kernel\n", 93 | "wget -qO- https://gist.github.com/wenta0g/67289a9b2e54b8128109abb3aff2194b/archive/0707f5d61d156ce2830505679994b0f1a606589b.tar.gz | tar xvz --strip-components=1\n", 94 | "python install_ipc_proxy_kernel.py --kernel=java --implementation=ipc_proxy_kernel.py" 95 | ] 96 | }, 97 | { 98 | "cell_type": "code", 99 | "execution_count": null, 100 | "id": "4163c715", 101 | "metadata": { 102 | "id": "4163c715", 103 | "vscode": { 104 | "languageId": "java" 105 | } 106 | }, 107 | "outputs": [], 108 | "source": [ 109 | "%%loadFromPOM\n", 110 | "\n", 111 | "\n", 112 | " junit\n", 113 | " junit\n", 114 | " 4.13.2\n", 115 | "" 116 | ] 117 | }, 118 | { 119 | "cell_type": "markdown", 120 | "id": "3ce4902d", 121 | "metadata": { 122 | "id": "3ce4902d" 123 | }, 124 | "source": [ 125 | "The following is a basic Java implementation of `ToLower`." 126 | ] 127 | }, 128 | { 129 | "cell_type": "code", 130 | "execution_count": null, 131 | "id": "f42ee996", 132 | "metadata": { 133 | "id": "f42ee996", 134 | "vscode": { 135 | "languageId": "java" 136 | } 137 | }, 138 | "outputs": [], 139 | "source": [ 140 | "public class ToLower {\n", 141 | "\n", 142 | " static final int MAX_STRING = 80;\n", 143 | " \n", 144 | " public static char[] toLower(String input)\n", 145 | " {\n", 146 | " //Scanner scan = new Scanner(System.in);\n", 147 | " char[] string = subString(input, 0, MAX_STRING).toCharArray();\n", 148 | " for (int i = 0; i < string.length - 1; i++) {\n", 149 | " if (string[i] < 32 || string[i] == 127) {\n", 150 | " System.out.println(\"Illegal character found.\\n\");\n", 151 | " return \"Illegal\".toCharArray();\n", 152 | " }\n", 153 | " \n", 154 | " if (string[i] >= 65 || string[i] <= 90) {\n", 155 | " string[i] = (char) (string[i] + 'a' - 'A');\n", 156 | " }\n", 157 | " }\n", 158 | " return string;\n", 159 | " }\n", 160 | " \n", 161 | " public static void main(String[] args) {\n", 162 | " System.out.println(toLower(\"€\"));\n", 163 | " }\n", 164 | " \n", 165 | " public static String subString(String myString, int start, int length) {\n", 166 | " return myString.substring(start, Math.min(start + length, myString.length()));\n", 167 | " }\n", 168 | " \n", 169 | "}" 170 | ] 171 | }, 172 | { 173 | "cell_type": "code", 174 | "execution_count": null, 175 | "id": "fa0d654e", 176 | "metadata": { 177 | "id": "fa0d654e", 178 | "vscode": { 179 | "languageId": "java" 180 | } 181 | }, 182 | "outputs": [], 183 | "source": [ 184 | "import org.junit.Assert;\n", 185 | "import java.util.Arrays;\n", 186 | "import java.util.Collection;\n", 187 | "\n", 188 | "import org.junit.Test;\n", 189 | "import org.junit.runner.JUnitCore;\n", 190 | "import org.junit.runner.Result;\n", 191 | "import org.junit.runner.RunWith;\n", 192 | "import org.junit.runner.notification.Failure;\n", 193 | "import org.junit.runners.Parameterized;\n", 194 | "\n", 195 | "import junit.framework.TestCase;\n", 196 | "\n", 197 | "@RunWith(Parameterized.class)\n", 198 | "public class TestToLower extends TestCase {\n", 199 | " @Parameterized.Parameter(0)\n", 200 | " public String actual;\n", 201 | " @Parameterized.Parameter(1)\n", 202 | " public char[] expected;\n", 203 | " \n", 204 | " @Parameterized.Parameters(name = \"{index}: actual: {0} expected:{1}\")\n", 205 | " public static Collection data() {\n", 206 | "\n", 207 | " \n", 208 | " Object[][] data = new Object[][]{\n", 209 | " // Your Test cases start here\n", 210 | "\n", 211 | " {\"KKK\", new char[] {'k', 'k', 'k'}},\n", 212 | " // Your Test cases end here\n", 213 | " };\n", 214 | " return Arrays.asList(data);\n", 215 | " }\n", 216 | " \n", 217 | " @Test\n", 218 | " public void testLower() {\n", 219 | " Assert.assertArrayEquals(expected, ToLower.toLower(actual));\n", 220 | " }\n", 221 | " \n", 222 | " public static void main(String[] args) {\n", 223 | "\n", 224 | " }\n", 225 | "}" 226 | ] 227 | }, 228 | { 229 | "cell_type": "code", 230 | "execution_count": null, 231 | "id": "34edaccf", 232 | "metadata": { 233 | "id": "34edaccf", 234 | "outputId": "48e9a17a-a347-4873-d309-f74dbb8846bb", 235 | "scrolled": true, 236 | "vscode": { 237 | "languageId": "java" 238 | } 239 | }, 240 | "outputs": [ 241 | { 242 | "name": "stdout", 243 | "output_type": "stream", 244 | "text": [ 245 | "testLower[0: actual: KKK expected:[C@656a01f0](REPL.$JShell$26$TestToLower): arrays first differed at element [2]; expected: but was:\n", 246 | "Total run count: 1, Failed run count: 1\n" 247 | ] 248 | } 249 | ], 250 | "source": [ 251 | "Result result = JUnitCore.runClasses(TestToLower.class);\n", 252 | "for (Failure failure : result.getFailures()) {\n", 253 | " System.out.println(failure.toString());\n", 254 | "}\n", 255 | "System.out.println(String.format(\"Total run count: %s, Failed run count: %s\", result.getRunCount(), result.getFailureCount()));" 256 | ] 257 | }, 258 | { 259 | "cell_type": "markdown", 260 | "id": "87be6536", 261 | "metadata": { 262 | "id": "87be6536" 263 | }, 264 | "source": [ 265 | "### Second Program\n", 266 | "\n", 267 | "The idea behind the algorithm for finding roots is to look at the\n", 268 | "interval $[Lower,Upper]$ and bisect it (hence the name of the algorithm)\n", 269 | "and find the midpoint of the interval $x_r$. If we know that $Lower$ is\n", 270 | "negative, and $Upper$ is positive then there must be root in the\n", 271 | "interval, provided that the function is continuous. If the value of $f$\n", 272 | "at $x_r$ is positive then the root must be in the interval\n", 273 | "$[Lower,x_r]$. If the value of $f$ at $x_r$ is negative then the root\n", 274 | "must be in the interval $[x_r,Upper]$. The algorithm should converge to\n", 275 | "the root because the length of the interval is getting smaller every\n", 276 | "time (in fact the length of the interval is halved every time).\n", 277 | "\n", 278 | "The following is a basic Java implementation of `BiSection`." 279 | ] 280 | }, 281 | { 282 | "cell_type": "code", 283 | "execution_count": null, 284 | "id": "0a5c74e3", 285 | "metadata": { 286 | "id": "0a5c74e3", 287 | "vscode": { 288 | "languageId": "java" 289 | } 290 | }, 291 | "outputs": [], 292 | "source": [ 293 | "public class Bisection{\n", 294 | "\n", 295 | " static final int MAX_INT = 65535;\n", 296 | " \n", 297 | " static double bisection(double lower, double upper, double error, int max) {\n", 298 | " \n", 299 | " double sign = 0.0; /* Test for the sign of the midpoint xr. */\n", 300 | " double ea = MAX_INT; /* Calculated error value. */\n", 301 | " double xrold = 0.0; /* Previous estimate. */\n", 302 | " double xr = 0.0; /* Current x estimate for the root. */\n", 303 | " double fr = 0.0; /* Current value of f. */\n", 304 | " double fl = 0.0; /* Value of f at the lower end of the interval. */\n", 305 | " int iteration = 0; /* For keeping track of the number of iterations. */\n", 306 | " \n", 307 | " fl = func(lower);\n", 308 | " while ((ea > error && iteration < max)) {\n", 309 | " \n", 310 | " /* Start by memorising the old estimate in xrold and then calculate\n", 311 | " the new estimate and store in fr */\n", 312 | " xrold = xr;\n", 313 | " xr = (lower + upper) / 2;\n", 314 | " fr = func(xr);\n", 315 | " iteration++;\n", 316 | " /* Estimate the percentage error and store in ea. */\n", 317 | " if (xr != 0) {\n", 318 | " ea = Math.abs((xr - xrold)/xr) * 100;\n", 319 | " }\n", 320 | " \n", 321 | " /* To know whether fr has the same sign as f(Lower) or f(Upper) is easy:\n", 322 | " we know that f(Lower) is negative and we know that f(Upper) is positive.\n", 323 | " Multiple fr by f(Lower) and if the result is positive then fr must be\n", 324 | " negative. If the result is negative then fr must be positive. */\n", 325 | " \n", 326 | " sign = func(lower) * fr;\n", 327 | " if (sign < 0)\n", 328 | " upper = xr;\n", 329 | " else if (sign > 0)\n", 330 | " lower = xr;\n", 331 | " else\n", 332 | " ea = 0;\n", 333 | " System.out.println(String.format(\"iteration %d = (%f, %f, %f, %f, %f)\\n\", iteration, lower, upper, xr, ea, sign));\n", 334 | " }\n", 335 | " return xr;\n", 336 | " }\n", 337 | " \n", 338 | " static double func(double x) {\n", 339 | " return x - 2;\n", 340 | " }\n", 341 | "}" 342 | ] 343 | }, 344 | { 345 | "cell_type": "code", 346 | "execution_count": null, 347 | "id": "ab6dd27a", 348 | "metadata": { 349 | "id": "ab6dd27a", 350 | "vscode": { 351 | "languageId": "java" 352 | } 353 | }, 354 | "outputs": [], 355 | "source": [ 356 | "import java.util.Arrays;\n", 357 | "import java.util.Collection;\n", 358 | "\n", 359 | "import org.junit.Test;\n", 360 | "import org.junit.runner.JUnitCore;\n", 361 | "import org.junit.runner.Result;\n", 362 | "import org.junit.runner.RunWith;\n", 363 | "import org.junit.runner.notification.Failure;\n", 364 | "import org.junit.runners.Parameterized;\n", 365 | "\n", 366 | "import junit.framework.TestCase;\n", 367 | "\n", 368 | "@RunWith(Parameterized.class)\n", 369 | "public class TestBisection extends TestCase {\n", 370 | " \n", 371 | " @Parameterized.Parameter(0)\n", 372 | " public double lower;\n", 373 | " @Parameterized.Parameter(1)\n", 374 | " public double upper;\n", 375 | " @Parameterized.Parameter(2)\n", 376 | " public double error;\n", 377 | " @Parameterized.Parameter(3)\n", 378 | " public int max;\n", 379 | " @Parameterized.Parameter(4)\n", 380 | " public double results;\n", 381 | "\n", 382 | " @Parameterized.Parameters(name = \"{index}: lower: {0} upper:{1} error:{2} iterations:{3} results:{5}\")\n", 383 | " public static Collection data() {\n", 384 | " Object[][] data = new Object[][]{\n", 385 | " // Your Test cases start here\n", 386 | " // Please follow the pattern: lower, upper, error, iterations, expected results\n", 387 | " {-1.0, 7.0, 1, 10, 2.0},\n", 388 | " {-1.0, 7.0, 1, 10, 2.0}\n", 389 | " // Your Test cases end here\n", 390 | " };\n", 391 | " return Arrays.asList(data);\n", 392 | " }\n", 393 | "\n", 394 | " @Test\n", 395 | " public void testBisection() {\n", 396 | " assertEquals(results, Bisection.bisection(lower, upper, error, max));\n", 397 | " }\n", 398 | "}" 399 | ] 400 | }, 401 | { 402 | "cell_type": "code", 403 | "execution_count": null, 404 | "id": "68dc9440", 405 | "metadata": { 406 | "id": "68dc9440", 407 | "outputId": "8d8129ed-7d98-4b29-cedb-af3984f3b145", 408 | "vscode": { 409 | "languageId": "java" 410 | } 411 | }, 412 | "outputs": [ 413 | { 414 | "name": "stdout", 415 | "output_type": "stream", 416 | "text": [ 417 | "iteration 1 = (-1.000000, 3.000000, 3.000000, 100.000000, -3.000000)\n", 418 | "\n", 419 | "iteration 2 = (1.000000, 3.000000, 1.000000, 200.000000, 3.000000)\n", 420 | "\n", 421 | "iteration 3 = (1.000000, 3.000000, 2.000000, 0.000000, -0.000000)\n", 422 | "\n", 423 | "iteration 1 = (-1.000000, 3.000000, 3.000000, 100.000000, -3.000000)\n", 424 | "\n", 425 | "iteration 2 = (1.000000, 3.000000, 1.000000, 200.000000, 3.000000)\n", 426 | "\n", 427 | "iteration 3 = (1.000000, 3.000000, 2.000000, 0.000000, -0.000000)\n", 428 | "\n", 429 | "Total run count: 2, Failed run count: 0\n" 430 | ] 431 | } 432 | ], 433 | "source": [ 434 | "Result result = JUnitCore.runClasses(TestBisection.class);\n", 435 | "for (Failure failure : result.getFailures()) {\n", 436 | " System.out.println(failure.toString());\n", 437 | "}\n", 438 | "System.out.println(String.format(\"Total run count: %s, Failed run count: %s\", result.getRunCount(), result.getFailureCount()));" 439 | ] 440 | }, 441 | { 442 | "cell_type": "markdown", 443 | "id": "59164571", 444 | "metadata": { 445 | "id": "59164571" 446 | }, 447 | "source": [ 448 | "## Your Tasks\n", 449 | "\n", 450 | "Repeat these tasks for both programs.\n", 451 | "\n", 452 | "### Task 1\n", 453 | "Standard analysis: Determine the input/output domains and the\n", 454 | "input/output conditions (if any).\n", 455 | "\n", 456 | "### Task 2\n", 457 | "Use the specification, domains and conditions to write a test oracle that determines if an\n", 458 | "arbitrary test input is correct, incorrect or otherwise undecidable.\n", 459 | "\n", 460 | "### Task 3\n", 461 | "Determine an automated means for generating random test cases by selection points from the input set.\n" 462 | ] 463 | } 464 | ], 465 | "metadata": { 466 | "colab": { 467 | "include_colab_link": true, 468 | "name": "SWEN90006_Tutorial_06.ipynb", 469 | "provenance": [] 470 | }, 471 | "kernelspec": { 472 | "display_name": "Java", 473 | "language": "java", 474 | "name": "java" 475 | }, 476 | "language_info": { 477 | "codemirror_mode": "java", 478 | "file_extension": ".jshell", 479 | "mimetype": "text/x-java-source", 480 | "name": "Java", 481 | "pygments_lexer": "java", 482 | "version": "10.0.2+13" 483 | } 484 | }, 485 | "nbformat": 4, 486 | "nbformat_minor": 5 487 | } 488 | -------------------------------------------------------------------------------- /SWEN90006_Tutorial_7.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "88f8f176", 6 | "metadata": { 7 | "id": "9f6077ed" 8 | }, 9 | "source": [ 10 | "# SWEN90006 Tutorial 7" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "id": "7abca9bb", 16 | "metadata": {}, 17 | "source": [ 18 | "**NOTE** You are expected to prepare for this tutorial by sketching\n", 19 | "answers to the tasks and questions before attending the tutorial." 20 | ] 21 | }, 22 | { 23 | "cell_type": "markdown", 24 | "id": "a39f5369", 25 | "metadata": { 26 | "id": "97e7daf0" 27 | }, 28 | "source": [ 29 | "## Introduction\n", 30 | "The aim of this tutorial is to get you thinking about software security\n", 31 | "and vulnerabilities, and the applicability of different kinds of\n", 32 | "security testing.\n", 33 | "\n", 34 | "As a first step, think about what security testing is, and why we would\n", 35 | "want to perform security testing on our software." 36 | ] 37 | }, 38 | { 39 | "cell_type": "markdown", 40 | "id": "53758b73", 41 | "metadata": { 42 | "id": "46680c7b" 43 | }, 44 | "source": [ 45 | "## The Bitmap File Format\n", 46 | "\n", 47 | "BMP is an historical image file format that we will use in this\n", 48 | "tutorial. We will consider a simple class of BMP files whose format is\n", 49 | "as follows. (Specifically, we consider here BMP files with no\n", 50 | "compression, and in which each pixel is 32-bits wide in order to avoid\n", 51 | "issues of padding; see\n", 52 | " and\n", 53 | " for more details.)\n", 54 | "\n", 55 | "| Offset | Size (in bytes) | Description |\n", 56 | "|--------|------------------------------|--------------------------------------------------------------------|\n", 57 | "| 0 | 1 | first byte of signature, must be 0x42 (the ASCII character 'B') |\n", 58 | "| 1 | 1 | second byte of signature, must be 0x4D (the ASCII character 'M') |\n", 59 | "| 2 | 4 | size of the BMP file in bytes (unreliable, ignored) |\n", 60 | "| 6 | 2 | Must be zero |\n", 61 | "| 8 | 2 | Must be zero |\n", 62 | "| 10 | 4 | Must be the value 54 (i.e. 0x00000036) |\n", 63 | "| 14 | 4 | Must be the value 40 (i.e. 0x00000028) |\n", 64 | "| 18 | 4 | *Width* (image width in pixels, as signed integer) |\n", 65 | "| 22 | 4 | *Height* (image height in pixels, as signed integer) |\n", 66 | "| 26 | 2 | Must be one |\n", 67 | "| 28 | 2 | Number of bits per pixel (must be 32) |\n", 68 | "| 30 | 4 | Compression type (must be 0 = no compression) |\n", 69 | "| 34 | 4 | Size of image data in bytes (must be 4\\**Width*\\**Height*) |\n", 70 | "| 38 | 4 | unreliable (ignored) |\n", 71 | "| 42 | 4 | unreliable (ignored) |\n", 72 | "| 46 | 4 | Must be zero |\n", 73 | "| 50 | 4 | Must be zero |\n", 74 | "| 54 | 4\\**Width*\\**Height* | Pixel data, laid out in rows |\n", 75 | "\n", 76 | "The first byte (offset 0) of a valid BMP file is the character 'B'; the\n", 77 | "second byte (offset 1) is the character 'M'. The 3rd to 6th bytes\n", 78 | "(offsets 2 to 5 inclusive) indicate the total length of the BMP file but\n", 79 | "are unreliable in practice and so let us assume that they are ignored by\n", 80 | "all BMP parsing code. The 7th and 8th bytes (offsets 6 and 7) are\n", 81 | "interpreted as a 2-byte integer that must be zero, i.e. each of these\n", 82 | "bytes must be zero. The same is true for the 9th and 10th bytes (offsets\n", 83 | "8 and 9), and so on." 84 | ] 85 | }, 86 | { 87 | "cell_type": "markdown", 88 | "id": "cfb0a548", 89 | "metadata": { 90 | "id": "59164571" 91 | }, 92 | "source": [ 93 | "## Your Tasks\n", 94 | "\n", 95 | "\n", 96 | "### Question 1\n", 97 | "Imagine you are choosing a value for each of the fields in the table\n", 98 | "above *in order*, i.e. you first choose a value for the first byte of\n", 99 | "the file, then choose a value for the second byte of the file, then for\n", 100 | "following 4-bytes, and so on. For each field, identify the total number\n", 101 | "of valid values there are to choose from, assuming you have already\n", 102 | "chosen values for all fields that have come before.\n", 103 | "\n", 104 | "### Question 2\n", 105 | "The BMP header (i.e. everything excluding the pixel data) as described\n", 106 | "above has a fixed length of 54 bytes. Using the answer from the previous\n", 107 | "question or otherwise, what is the probability that a (uniformly)\n", 108 | "randomly generated string of 54 bytes is a valid BMP header?\n", 109 | "\n", 110 | "### Question 3\n", 111 | "Suppose you have a valid 54-byte header and you mutate an arbitrary\n", 112 | "(uniformly randomly chosen) byte in the header to a new value (different\n", 113 | "from its original value). What is the probability of producing a valid\n", 114 | "header?\n", 115 | "\n", 116 | "### Question 4\n", 117 | "Imagine you had to write a fuzzer to fuzz some BMP processing code that\n", 118 | "processed BMP files of the format described above. If you had to choose\n", 119 | "between generating completely random inputs vs. using random mutation on\n", 120 | "existing BMP files, which strategy would you choose?\n" 121 | ] 122 | } 123 | ], 124 | "metadata": { 125 | "colab": { 126 | "include_colab_link": true, 127 | "name": "SWEN90006_Tutorial_06.ipynb", 128 | "provenance": [] 129 | }, 130 | "kernelspec": { 131 | "display_name": "Java", 132 | "language": "java", 133 | "name": "java" 134 | }, 135 | "language_info": { 136 | "codemirror_mode": "java", 137 | "file_extension": ".jshell", 138 | "mimetype": "text/x-java-source", 139 | "name": "Java", 140 | "pygments_lexer": "java", 141 | "version": "10.0.2+13" 142 | } 143 | }, 144 | "nbformat": 4, 145 | "nbformat_minor": 5 146 | } 147 | -------------------------------------------------------------------------------- /SWEN90006_Tutorial_8.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "a2f8b49d", 6 | "metadata": { 7 | "id": "9f6077ed" 8 | }, 9 | "source": [ 10 | "# SWEN90006 Tutorial 8" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "id": "849ea99f", 16 | "metadata": { 17 | "id": "97e7daf0" 18 | }, 19 | "source": [ 20 | "## Introduction\n", 21 | "\n", 22 | "The aim of this tutorial is for you to familiarise yourself with code coverage-guided fuzzing tools like AFL. In the class exercise last week (Week 8), we used generation-based/model-based black-box fuzzing tools like Peach fuzzer to generate inputs to trigger the faults in two versions of the read_and_process program. In this tutorial, you will use AFL to do the same task. " 23 | ] 24 | }, 25 | { 26 | "cell_type": "markdown", 27 | "id": "9a3f3550", 28 | "metadata": { 29 | "id": "46680c7b" 30 | }, 31 | "source": [ 32 | "## Working with programs\n", 33 | "\n", 34 | "Following the instructions at https://github.com/SWEN90006-2021/security-testing to setup a Docker image and Docker container.\n", 35 | "\n", 36 | "### First program: read_and_process_v1.c\n", 37 | "\n", 38 | "To trigger the fault, called FAULT-1, in this simpler version of read_and_process, AFL needs to generate an input file that satisfies the following conditions:\n", 39 | "-\tThe file should adhere to the structure of the expected file format. Recall that a valid file starts with a 4-byte \"signature\", followed by a list of chunks and each chunk has three parts: i) a chunk type stored in 4 bytes, ii) a 4-byte data length, and iii) the chunk data.\n", 40 | "-\tThe list of chunks should have at least one data chunk of the \"BOOM\" type.\n", 41 | "\n", 42 | "### Your tasks\n", 43 | "\n", 44 | "Compile read_and_process_v1.c with afl-clang-fast so that AFL can be used to fuzz test the generated binary with code coverage feedback enabled.\n", 45 | "\n", 46 | "```bash\n", 47 | "afl-clang-fast -g -o read_and_process_v1 read_and_process_v1.c\n", 48 | "```\n", 49 | "Run AFL to fuzz test the program in four settings. If your computer has enough CPU cores (>= 4 cores), you can start four docker containers and run four settings at the same time to speed up the experiments. You can stop AFL by typing down the combination \"Ctrl + C\". You can also set up a timeout for each command if you wish by using the timeout command (see https://linuxize.com/post/timeout-command-in-linux/).\n", 50 | "\n", 51 | "#### Setting-1\n", 52 | "Use only a random file, containing a number like \"1234\", as seed input.\n", 53 | "\n", 54 | "```bash\n", 55 | "mkdir corpus-random\n", 56 | "echo \"1234\" > corpus-random/random_file\n", 57 | "afl-fuzz -d -i corpus-random -o out-setting-1 ./read_and_process_v1 @@\n", 58 | "```\n", 59 | "\n", 60 | "If you want to run afl-fuzz fuzzer for 5 minutes, you can use this command\n", 61 | "\n", 62 | "```bash\n", 63 | "timeout 5m afl-fuzz -d -i corpus-random -o out-setting-1 ./read_and_process_v1 @@\n", 64 | "```\n", 65 | "#### Setting-2\n", 66 | "Use the same seed corpus in Setting-1 and use a so-called fuzzing dictionary. A fuzzing dictionary contains predefined tokens that can be randomly inserted into the generated input.\n", 67 | "\n", 68 | "Create a file named fuzz.dict that contains three tokens as below. Inside the Docker container, you can use simple text editors like vim or nano to create this file.\n", 69 | "\n", 70 | "```\n", 71 | "\"ABCD\"\n", 72 | "\"BOOM\"\n", 73 | "\"CHUK\"\n", 74 | "```\n", 75 | "\n", 76 | "And run the following fuzzing command. The \"-x\" option is used to specify a fuzzing dictionary.\n", 77 | "\n", 78 | "```bash\n", 79 | "afl-fuzz -d -x fuzz.dict -i corpus-random -o out-setting-2 ./read_and_process_v1 @@\n", 80 | "```\n", 81 | "\n", 82 | "#### Setting-3\n", 83 | "Use a seed corpus containing a valid input file that adheres to the specified format. The \"printf\" command is used to generate a valid file that has a single chunk of type \"CHUK\" and the chunk's data consists of four bytes. Note that all numbers are stored in little-endian order so \"\\x04\\x00\\x00\\x00\" is 0x04 in hexadecimal and 4 in decimal.\n", 84 | "\n", 85 | "```bash\n", 86 | "mkdir corpus-valid\n", 87 | "printf \"ABCDCHUK\\x04\\x00\\x00\\x00\\x00\\x00\\x00\\x00\" > corpus-valid/valid_file\n", 88 | "afl-fuzz -d -i corpus-valid -o out-setting-3 ./read_and_process_v1 @@\n", 89 | "```\n", 90 | "\n", 91 | "#### Setting-4\n", 92 | "Use the same seed corpus in Setting-3 together with the fuzzing dictionary in Setting-2.\n", 93 | "\n", 94 | "```bash\n", 95 | "afl-fuzz -d -x fuzz.dict -i corpus-valid -o out-setting-4 ./read_and_process_v1 @@\n", 96 | "```\n", 97 | "\n", 98 | "Discuss the results in the four settings with a focus on the pros and cons of each setting. The crash-triggering inputs should be found in out-setting-*/crashes folder where normal inputs should be found in out-setting-*/queue folder.\n", 99 | "\n", 100 | "### Second program: read_and_process_v2.c\n", 101 | "\n", 102 | "To trigger the fault in this version of read_and_process, in addition to FAULT-1's conditions, AFL needs to generate an input file that satisfies the following conditions:\n", 103 | "-\tThe data of the BOOM chunk contains two 4-byte integer numbers named x and y.\n", 104 | "-\tThe values of x and y must satisfy this constraint: (x + y > 283) && (x + y < 286)\n", 105 | "\n", 106 | "### Your tasks:\n", 107 | "\n", 108 | "Compile read_and_process_v2.c with afl-clang-fast.\n", 109 | "\n", 110 | "```bash\n", 111 | "afl-clang-fast -g -o read_and_process_v2 read_and_process_v2.c\n", 112 | "```\n", 113 | "\n", 114 | "#### Setting-5\n", 115 | "Use a seed corpus containing a valid input file that adheres to the specified format.\n", 116 | "\n", 117 | "```bash\n", 118 | "afl-fuzz -d -i corpus-valid -o out-setting-5 ./read_and_process_v2 @@\n", 119 | "```\n", 120 | "\n", 121 | "#### Setting-6\n", 122 | "Use the same seed corpus in Setting-5 together with a fuzzing dictionary.\n", 123 | "\n", 124 | "```bash\n", 125 | "afl-fuzz -d -x fuzz.dict -i corpus-valid -o out-setting-6 ./read_and_process_v2 @@\n", 126 | "```\n", 127 | "\n", 128 | "Discuss the results in the two settings with a focus on the pros and cons of each setting. The crash-triggering inputs should be found in out-setting-*/crashes folder where normal inputs should be found in out-setting-*/queue folder." 129 | ] 130 | }, 131 | { 132 | "cell_type": "code", 133 | "execution_count": null, 134 | "id": "2ef001ee", 135 | "metadata": {}, 136 | "outputs": [], 137 | "source": [] 138 | } 139 | ], 140 | "metadata": { 141 | "colab": { 142 | "include_colab_link": true, 143 | "name": "SWEN90006_Tutorial_06.ipynb", 144 | "provenance": [] 145 | }, 146 | "kernelspec": { 147 | "display_name": "Java", 148 | "language": "java", 149 | "name": "java" 150 | }, 151 | "language_info": { 152 | "codemirror_mode": "java", 153 | "file_extension": ".jshell", 154 | "mimetype": "text/x-java-source", 155 | "name": "Java", 156 | "pygments_lexer": "java", 157 | "version": "10.0.2+13" 158 | } 159 | }, 160 | "nbformat": 4, 161 | "nbformat_minor": 5 162 | } 163 | -------------------------------------------------------------------------------- /SWEN90006_Tutorial_8_2024.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "a2f8b49d", 6 | "metadata": { 7 | "id": "9f6077ed" 8 | }, 9 | "source": [ 10 | "# SWEN90006 Tutorial 8" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "id": "849ea99f", 16 | "metadata": { 17 | "id": "97e7daf0" 18 | }, 19 | "source": [ 20 | "## Introduction\n", 21 | "\n", 22 | "The aim of this tutorial is for you to familiarise yourself with generation-based and mutation-based fuzzing. In today's session, we will first reflect on mutation-based fuzzing a bit more using last week's example. And then, we will use generation-based/model-based black-box fuzzing tools like Peach fuzzer to generate inputs to trigger the faults in two versions of the read_and_process program. " 23 | ] 24 | }, 25 | { 26 | "cell_type": "markdown", 27 | "id": "9a3f3550", 28 | "metadata": { 29 | "id": "46680c7b" 30 | }, 31 | "source": [ 32 | "## Mutation-based fuzzing (cont'd)\n", 33 | "\n", 34 | "Please recap the BMP header excecise, review the concept of Mutation-based fuzzing, and answer Question 3 and Question 4 from last week again. \n", 35 | "\n", 36 | "### Question 3\n", 37 | "Suppose you have a valid 54-byte header and you mutate an arbitrary\n", 38 | "(uniformly randomly chosen) byte in the header to a new value (different\n", 39 | "from its original value). What is the probability of producing a valid\n", 40 | "header?\n", 41 | "\n", 42 | "### Question 4\n", 43 | "Imagine you had to write a fuzzer to fuzz some BMP processing code that\n", 44 | "can process BMP files of the format described above. If you had to choose\n", 45 | "between generating completely random inputs vs. performing random mutation \n", 46 | "on existing (valid) BMP files, which strategy would you choose?\n" 47 | ] 48 | }, 49 | { 50 | "cell_type": "markdown", 51 | "id": "2ef001ee", 52 | "metadata": {}, 53 | "source": [ 54 | "\n", 55 | "## Generation-based fuzzing\n", 56 | "\n", 57 | "\n", 58 | "### Building a Docker Container\n", 59 | "\n", 60 | "We provided a docker container that has all tools introduced in the lecture. This docker will be used to help you understand fuzzing better, reproduce the demos during the lecture, and carry out fuzzing experiments in tutorials for the next few weeks. \n", 61 | "\n", 62 | "Following the instructions at https://github.com/SWEN90006-2021/security-testing to setup a Docker image and Docker container.\n", 63 | "\n", 64 | "\n", 65 | "### Week 8 in-class exercise\n", 66 | "\n", 67 | "This part of the instructions are the same as `Week 8 in-class exercise: generation-based fuzzing` on Canvas.\n", 68 | "\n", 69 | "We will look at two exercises in which you are asked to apply these fuzzing techniques to discover the faults in two versions of a program named `read_and_process.c` (stored in `read_and_process.zip`). This program mimics some functionalities of media processing libraries like LibPNG. The program takes a file as input and the file is expected to adhere to a specific format. A valid file starts with a 4-byte \"signature\". After that, the file contains a list of chunks and each chunk has three parts: i) a chunk type stored in 4 bytes, ii) a 4-byte data length, and iii) the chunk data.\n", 70 | "\n", 71 | "The below images taken from the lecture slides illustrates the file format:\n", 72 | "\n", 73 | "![File Format](figures/Input_structure_tut8.png)\n", 74 | "\n", 75 | "### Question 1: Manual analysis\n", 76 | "\n", 77 | "What is the fault in [read_and_process_v1.c](https://github.com/SWEN90006-2021/security-testing/blob/main/read_and_process_v1.c)? What are the conditions to trigger the fault?\n", 78 | "\n", 79 | "### Question 2: Write an input model for the given file format \n", 80 | "\n", 81 | "Create a new file with name `input_model.xml`\n", 82 | "\n", 83 | "Hint: the input model is also on the lecture slides\n", 84 | "\n", 85 | "### Question 3: Generation-based fuzzing\n", 86 | "Use the input model and use generation-based fuzzing (`generation_fuzzer.sh`) to automatically generate an input to trigger that fault. You would need to update the fuzzer scripts to capture SIGABORT (return code = 134) instead of SIGFAULT (return code = 139).\n", 87 | "\n", 88 | "
\n", 89 | "\n", 90 | "```shell\n", 91 | "// First, compile the buggy program read_and_process_v1.c\n", 92 | "cd $WORKDIR\n", 93 | "gcc -o read_and_process_v1 read_and_process_v1.c\n", 94 | "\n", 95 | "// Next, run generation-based fuzzer to fuzz the read_and_process_v1 program\n", 96 | "generation_fuzzer.sh ./read_and_process_v1 input_model.xml 20 results-no-seeds\n", 97 | "```\n", 98 | "
\n", 99 | "\n", 100 | "### Question 4: Work on another program using all steps from questions 1 - 3\n", 101 | "What is the fault in [read_and_process_v2.c](https://github.com/SWEN90006-2021/security-testing/blob/main/read_and_process_v2.c)? \n", 102 | "What are the conditions to trigger that fault? \n", 103 | "Is the input model written in Question-2 helpful to discover that fault? If it does not work, discuss the ideas to fuzz test this program.\n" 104 | ] 105 | } 106 | ], 107 | "metadata": { 108 | "colab": { 109 | "include_colab_link": true, 110 | "name": "SWEN90006_Tutorial_06.ipynb", 111 | "provenance": [] 112 | }, 113 | "kernelspec": { 114 | "display_name": "Java", 115 | "language": "java", 116 | "name": "java" 117 | }, 118 | "language_info": { 119 | "codemirror_mode": "java", 120 | "file_extension": ".jshell", 121 | "mimetype": "text/x-java-source", 122 | "name": "Java", 123 | "pygments_lexer": "java", 124 | "version": "10.0.2+13" 125 | } 126 | }, 127 | "nbformat": 4, 128 | "nbformat_minor": 5 129 | } 130 | -------------------------------------------------------------------------------- /SWEN90006_Tutorial_9.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "3adcba9a", 6 | "metadata": { 7 | "id": "9f6077ed" 8 | }, 9 | "source": [ 10 | "# SWEN90006 Tutorial 9" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "id": "960f7aae", 16 | "metadata": { 17 | "id": "97e7daf0" 18 | }, 19 | "source": [ 20 | "## Introduction\n", 21 | "\n", 22 | "The aim of this tutorial is to give you more experience with symbolic\n", 23 | "execution and how it can be used to verify software." 24 | ] 25 | }, 26 | { 27 | "cell_type": "markdown", 28 | "id": "e9c224d8", 29 | "metadata": { 30 | "id": "46680c7b" 31 | }, 32 | "source": [ 33 | "## Symbolic Execution\n", 34 | "\n", 35 | "Recall from the lecture that the aim of symbolic execution is to, in\n", 36 | "effect, execute *multiple* inputs at the same time -- possibly an\n", 37 | "infinite number. It does this by using symbolic values to represent\n", 38 | "inputs, instead of concrete values.\n", 39 | "\n", 40 | "A complete symbolic execution of a program produces a *symbolic\n", 41 | "execution tree*. Each path through the tree represents a single path\n", 42 | "through the program, including all inputs on that path. Each node along\n", 43 | "a path represents the symbolic values of variables at that point in the\n", 44 | "execution.\n", 45 | "\n", 46 | "\n", 47 | "## Tasks and Questions\n", 48 | "\n", 49 | "### Question 1\n", 50 | "\n", 51 | "Figure C.3 shows an implementation of a program that\n", 52 | "returns the minimum of two integers. Draw the complete symbolic\n", 53 | "execution tree for this program. In your execution tree, use the\n", 54 | "variables `X_0` and `Y_0` to represent the initial symbolic values of\n", 55 | "`x` and `y` respectively.\n", 56 | "\n", 57 | "At the return statement at line 10, assume the existence of a symbolic\n", 58 | "variable `RET`, to which the return value is assigned when a return\n", 59 | "statement is executed.\n", 60 | "\n", 61 | "```c\n", 62 | " 1. int min(int x, int y)\n", 63 | " 2. {\n", 64 | " 3. int minimum = 0;\n", 65 | " 4. if (x > y) {\n", 66 | " 5. minimum = y;\n", 67 | " 6. }\n", 68 | " 7. else if (y > x) {\n", 69 | " 8. minimum = x;\n", 70 | " 9. }\n", 71 | " 10. return minimum;\n", 72 | " 11. }\n", 73 | "```\n", 74 | "\n", 75 | "

Figure C.3: An implementation of the Min function

\n", 76 | "\n", 77 | "### Question 2\n", 78 | "Does the program in Figure C.3 ensure the precondition that the number\n", 79 | "returned is always the minimum; i.e. that `RET` is the minimum number of\n", 80 | "`X_0` and `Y_0`?" 81 | ] 82 | }, 83 | { 84 | "cell_type": "markdown", 85 | "id": "c45d2585", 86 | "metadata": {}, 87 | "source": [] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": null, 92 | "id": "63604442", 93 | "metadata": {}, 94 | "outputs": [], 95 | "source": [] 96 | } 97 | ], 98 | "metadata": { 99 | "colab": { 100 | "include_colab_link": true, 101 | "name": "SWEN90006_Tutorial_06.ipynb", 102 | "provenance": [] 103 | }, 104 | "kernelspec": { 105 | "display_name": "Java", 106 | "language": "java", 107 | "name": "java" 108 | }, 109 | "language_info": { 110 | "codemirror_mode": "java", 111 | "file_extension": ".jshell", 112 | "mimetype": "text/x-java-source", 113 | "name": "Java", 114 | "pygments_lexer": "java", 115 | "version": "10.0.2+13" 116 | } 117 | }, 118 | "nbformat": 4, 119 | "nbformat_minor": 5 120 | } 121 | -------------------------------------------------------------------------------- /SWEN90006_Tutorial_9_2024.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "3adcba9a", 6 | "metadata": { 7 | "id": "9f6077ed" 8 | }, 9 | "source": [ 10 | "# SWEN90006 Tutorial 9" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "id": "960f7aae", 16 | "metadata": { 17 | "id": "97e7daf0" 18 | }, 19 | "source": [ 20 | "## Introduction\n", 21 | "\n", 22 | "The aim of this tutorial is for you to familiarise yourself with code coverage-guided fuzzing tools like AFL. In the class exercise last week (Week 8), we used generation-based/model-based black-box fuzzing tools like Peach fuzzer to generate inputs to trigger the faults in two versions of the read_and_process program. In this tutorial, you will use AFL to do the same task. " 23 | ] 24 | }, 25 | { 26 | "cell_type": "markdown", 27 | "id": "e9c224d8", 28 | "metadata": { 29 | "id": "46680c7b" 30 | }, 31 | "source": [ 32 | "## Working with programs\n", 33 | "\n", 34 | "We will use the same docker image that we built in Tutorial 8. You may use this command to list all docker images\n", 35 | "\n", 36 | "```bash\n", 37 | "docker ps -a\n", 38 | "```\n", 39 | "\n", 40 | "You may see the containers that you used from Week 8's tutorial:\n", 41 | "\n", 42 | "| CONTAINER ID | IMAGE | COMMAND | CREATED | STATUS | PORTS | NAMES |\n", 43 | "|--------------|-----------------|-------------|-------------|-------------------------|-------|-----------------|\n", 44 | "| SOME_ID | swen90006 | \"/bin/bash\" | 7 days ago | Exited / Up | | SOME_NAME |\n", 45 | "\n", 46 | "Then you can start the docker container again without creating a new one by:\n", 47 | "\n", 48 | "```bash\n", 49 | "# start the container, if the status is not up:\n", 50 | "docker start \n", 51 | "# enter the container's shell:\n", 52 | "docker exec -it /bin/bash\n", 53 | "```\n", 54 | "\n", 55 | "If you have not build the docker yet, please follow the instructions at https://github.com/SWEN90006-2021/security-testing to setup a Docker image and Docker container.\n", 56 | "\n", 57 | "### First program: read_and_process_v1.c\n", 58 | "\n", 59 | "To trigger the fault, called FAULT-1, in this simpler version of read_and_process, AFL needs to generate an input file that satisfies the following conditions:\n", 60 | "-\tThe file should adhere to the structure of the expected file format. Recall that a valid file starts with a 4-byte \"signature\", followed by a list of chunks and each chunk has three parts: i) a chunk type stored in 4 bytes, ii) a 4-byte data length, and iii) the chunk data.\n", 61 | "-\tThe list of chunks should have at least one data chunk of the \"BOOM\" type.\n", 62 | "\n", 63 | "### Your tasks\n", 64 | "\n", 65 | "Compile read_and_process_v1.c with afl-clang-fast so that AFL can be used to fuzz test the generated binary with code coverage feedback enabled.\n", 66 | "\n", 67 | "```bash\n", 68 | "afl-clang-fast -g -o read_and_process_v1 read_and_process_v1.c\n", 69 | "```\n", 70 | "Run AFL to fuzz test the program in four settings. If your computer has enough CPU cores (>= 4 cores), you can start four docker containers and run four settings at the same time to speed up the experiments. You can stop AFL by typing down the combination \"Ctrl + C\". You can also set up a timeout for each command if you wish by using the timeout command (see https://linuxize.com/post/timeout-command-in-linux/).\n", 71 | "\n", 72 | "#### Setting-1\n", 73 | "Use only a random file, containing a number like \"1234\", as seed input.\n", 74 | "\n", 75 | "```bash\n", 76 | "mkdir corpus-random\n", 77 | "echo \"1234\" > corpus-random/random_file\n", 78 | "afl-fuzz -d -i corpus-random -o out-setting-1 ./read_and_process_v1 @@\n", 79 | "```\n", 80 | "\n", 81 | "If you want to run afl-fuzz fuzzer for 5 minutes, you can use this command\n", 82 | "\n", 83 | "```bash\n", 84 | "timeout 5m afl-fuzz -d -i corpus-random -o out-setting-1 ./read_and_process_v1 @@\n", 85 | "```\n", 86 | "#### Setting-2\n", 87 | "Use the same seed corpus in Setting-1 and use a so-called fuzzing dictionary. A fuzzing dictionary contains predefined tokens that can be randomly inserted into the generated input.\n", 88 | "\n", 89 | "Create a file named fuzz.dict that contains three tokens as below. Inside the Docker container, you can use simple text editors like vim or nano to create this file.\n", 90 | "\n", 91 | "```\n", 92 | "\"ABCD\"\n", 93 | "\"BOOM\"\n", 94 | "\"CHUK\"\n", 95 | "```\n", 96 | "\n", 97 | "And run the following fuzzing command. The \"-x\" option is used to specify a fuzzing dictionary.\n", 98 | "\n", 99 | "```bash\n", 100 | "afl-fuzz -d -x fuzz.dict -i corpus-random -o out-setting-2 ./read_and_process_v1 @@\n", 101 | "```\n", 102 | "\n", 103 | "#### Setting-3\n", 104 | "Use a seed corpus containing a valid input file that adheres to the specified format. The \"printf\" command is used to generate a valid file that has a single chunk of type \"CHUK\" and the chunk's data consists of four bytes. Note that all numbers are stored in little-endian order so \"\\x04\\x00\\x00\\x00\" is 0x04 in hexadecimal and 4 in decimal.\n", 105 | "\n", 106 | "```bash\n", 107 | "mkdir corpus-valid\n", 108 | "printf \"ABCDCHUK\\x04\\x00\\x00\\x00\\x00\\x00\\x00\\x00\" > corpus-valid/valid_file\n", 109 | "afl-fuzz -d -i corpus-valid -o out-setting-3 ./read_and_process_v1 @@\n", 110 | "```\n", 111 | "\n", 112 | "#### Setting-4\n", 113 | "Use the same seed corpus in Setting-3 together with the fuzzing dictionary in Setting-2.\n", 114 | "\n", 115 | "```bash\n", 116 | "afl-fuzz -d -x fuzz.dict -i corpus-valid -o out-setting-4 ./read_and_process_v1 @@\n", 117 | "```\n", 118 | "\n", 119 | "Discuss the results in the four settings with a focus on the pros and cons of each setting. The crash-triggering inputs should be found in out-setting-*/crashes folder where normal inputs should be found in out-setting-*/queue folder.\n", 120 | "\n", 121 | "### Second program: read_and_process_v2.c\n", 122 | "\n", 123 | "To trigger the fault in this version of read_and_process, in addition to FAULT-1's conditions, AFL needs to generate an input file that satisfies the following conditions:\n", 124 | "-\tThe data of the BOOM chunk contains two 4-byte integer numbers named x and y.\n", 125 | "-\tThe values of x and y must satisfy this constraint: (x + y > 283) && (x + y < 286)\n", 126 | "\n", 127 | "### Your tasks:\n", 128 | "\n", 129 | "Compile read_and_process_v2.c with afl-clang-fast.\n", 130 | "\n", 131 | "```bash\n", 132 | "afl-clang-fast -g -o read_and_process_v2 read_and_process_v2.c\n", 133 | "```\n", 134 | "\n", 135 | "#### Setting-5\n", 136 | "Use a seed corpus containing a valid input file that adheres to the specified format.\n", 137 | "\n", 138 | "```bash\n", 139 | "afl-fuzz -d -i corpus-valid -o out-setting-5 ./read_and_process_v2 @@\n", 140 | "```\n", 141 | "\n", 142 | "#### Setting-6\n", 143 | "Use the same seed corpus in Setting-5 together with a fuzzing dictionary.\n", 144 | "\n", 145 | "```bash\n", 146 | "afl-fuzz -d -x fuzz.dict -i corpus-valid -o out-setting-6 ./read_and_process_v2 @@\n", 147 | "```\n", 148 | "\n", 149 | "### Discussion\n", 150 | "\n", 151 | "Discuss the results in the two settings with a focus on the pros and cons of each setting. The crash-triggering inputs should be found in out-setting-*/crashes folder where normal inputs should be found in out-setting-*/queue folder." 152 | ] 153 | }, 154 | { 155 | "cell_type": "markdown", 156 | "id": "c45d2585", 157 | "metadata": {}, 158 | "source": [] 159 | }, 160 | { 161 | "cell_type": "code", 162 | "execution_count": null, 163 | "id": "63604442", 164 | "metadata": { 165 | "vscode": { 166 | "languageId": "java" 167 | } 168 | }, 169 | "outputs": [], 170 | "source": [] 171 | } 172 | ], 173 | "metadata": { 174 | "colab": { 175 | "include_colab_link": true, 176 | "name": "SWEN90006_Tutorial_06.ipynb", 177 | "provenance": [] 178 | }, 179 | "kernelspec": { 180 | "display_name": "Java", 181 | "language": "java", 182 | "name": "java" 183 | }, 184 | "language_info": { 185 | "codemirror_mode": "java", 186 | "file_extension": ".jshell", 187 | "mimetype": "text/x-java-source", 188 | "name": "Java", 189 | "pygments_lexer": "java", 190 | "version": "10.0.2+13" 191 | } 192 | }, 193 | "nbformat": 4, 194 | "nbformat_minor": 5 195 | } 196 | -------------------------------------------------------------------------------- /figures/CFG-Tutorial-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SWEN90006/tutorials/e978ad3a613bfaffc622a515fe06c91bbef85095/figures/CFG-Tutorial-3.png -------------------------------------------------------------------------------- /figures/CFG-Tutorial-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SWEN90006/tutorials/e978ad3a613bfaffc622a515fe06c91bbef85095/figures/CFG-Tutorial-4.png -------------------------------------------------------------------------------- /figures/CFG-Tutorial-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SWEN90006/tutorials/e978ad3a613bfaffc622a515fe06c91bbef85095/figures/CFG-Tutorial-5.png -------------------------------------------------------------------------------- /figures/CFG1_tut4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SWEN90006/tutorials/e978ad3a613bfaffc622a515fe06c91bbef85095/figures/CFG1_tut4.png -------------------------------------------------------------------------------- /figures/Graph-State-Diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SWEN90006/tutorials/e978ad3a613bfaffc622a515fe06c91bbef85095/figures/Graph-State-Diagram.png -------------------------------------------------------------------------------- /figures/Input_structure_tut8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SWEN90006/tutorials/e978ad3a613bfaffc622a515fe06c91bbef85095/figures/Input_structure_tut8.png -------------------------------------------------------------------------------- /figures/LWIG-TTT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SWEN90006/tutorials/e978ad3a613bfaffc622a515fe06c91bbef85095/figures/LWIG-TTT.png -------------------------------------------------------------------------------- /figures/Log-Graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SWEN90006/tutorials/e978ad3a613bfaffc622a515fe06c91bbef85095/figures/Log-Graph.png -------------------------------------------------------------------------------- /figures/min-execution-tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SWEN90006/tutorials/e978ad3a613bfaffc622a515fe06c91bbef85095/figures/min-execution-tree.png --------------------------------------------------------------------------------