Bugtoberfest is officially over! I hope everyone who wanted to participate was able to complete the tutorials and find all the bugs! As the week is officially over, those of us who wrote these bug hunts wanted to share the intended bugs we wrote into them so y'all had an opportunity to check your work.
By the way, while Bugtoberfest is over, Spooktoberfest is this week's Fun Friday event - check out the details in the Spooktoberfest 2024 blog post!
But before getting to that, I wanted to share a bit about the origin of the name bug used for coding errors. While most believe the origin comes from a real moth getting comfy in a relay in the Mark II at Harvard in 1947, the word actually comes from the terms bugbear or bugaboo. The term bug as used to describe an issue or error in engineering and can be seen in use by Thomas Edison in 1878, well before it was used to describe software or hardware faults.
As a fun aside, us developer advocates had a debate to the origin of the term at a dinner during TechEd Virtual and I ruined many evenings by sharing this fun fact with everyone. I even had to read aloud an article to prove that it didn't originate from the Harvard moth (which was shared as folks found it really funny a bug was caused by a real bug), as I was met with such disbelief. As a result, I was told I had to include this "fun" fact and story somewhere in relation to Bugtoberfest.
Now that everyone is aware of the origin of bugs, check out each of the sections below to see the bugs we purposefully wrote into our individual bug hunts.
ABAP
Easy
CLASS ztest
DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
METHODS test_value.
METHODS test_value1.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS ztest
IMPLEMENTATION.
METHOD test_value2.
ENDMETHOD.
METHOD test_value1
ENDCLASS.
Bug 1: At line 17, missing full stop `.` after `METHOD test_value1`. Bug 2: At line 18, missing `ENDMETHOD` for `test_value1 METHOD`. Bug 3: At line 15, implemented Wrong Method `test_value2` instead of `test_value`.
Medium
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Carrier View - CDS Data Model'
@Search.searchable: true
define view entity ZTest
as selectfrom /dmo/flight as Flight
association [1] to /DMO/I_Carrier as _Airline
{
@UI.lineItem: [ { position: 10, label: 'Airline'} ]
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 0.7
@ObjectModel.text.association: '_Airline'
key Flight.carrier_id as AirlineID,
@UI.lineItem: [ { position: 20, label: 'Connection Number' } ]
key Flight.connection_id as ConnectionID,
@UI.lineItem: [ { position: 30, label: 'Flight Date' } ]
key Flight.flight_date as FlightDate,
@UI.lineItem: [ { position: 40, label: 'Price' } ]
@Semantics.amount.currencyCode: 'CurrencyCode'
Flight.price as Price,
Flight.currency_code as CurrencyCode,
@Semantics.amount.currencyCode: 'CurrencyCode'
case
when price <= 1000 or price is initial
then cast(price as /dmo/flight_price preserving type)
else
cast( 1000 + (cast(price as abap.numc(16,2)) - 1000 ) *
division(9,10,2) as /dmo/flight_price)
end as
/* Associations */
_Airline
}
Bug 1: At line 5, `select` from written as `selectfrom`.
Bug 2: At line 6, association statement is incomplete, should have `on $projection.AirlineID = _Airline.AirlineID` after `_Airline`.
Bug 3: At line 28, `end as` Variable Name missing and comma (,) missing after Variable name.
Bug 4: At line 26, `abap.numc` is a wrong data type, it should be `abap.dec`.
Hard
@AbapCatalog.viewEnhancementCategory: [#NONE]
@abapcatalog.sqlViewName: 'ZTESt1'
@AccessControl.authorizationCheck: '#NOT_REQUIRED'
@EndUserText.label: 'Test'
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED
}
define view entity ZTest!
with parameters
P_Currency :/dmo/currency_code
as select from /dmo/travel
association [0] to /DMO/I_Overall_Status_VH_Text as _Status on $projection.Status = _Status.OverallStatus
{
key travel_id as TravelId,
description as Description,
total_price as TotalPrice,
currency_code as CurrencyCode,
concat_with_space(cast(total_price as abap.char( 20) ),
$parameters.P_Curency,1) as AmountInCurrency,
@Consumption.valueHelpDefinition: [{ element: { name:
'/DMO/I_Overall_Status_VH',entity: 'OverallStatus' } }]
status as Status,
_Status.Text as OverallStatus,
}
Bug 1: At line 4, in the assignment of `$REPLY` to `answer`, `answer` should not be prefixed with `$`. (this is not Perl!)
Bug 2: At line 4, in the assignment, no spaces are allowed either before or after the equals symbol `=`.
Bug 3: At line 5, inside single quotes, variables like `$answer` are not expanded (double quotes are needed here).
Medium
#!/usr/bin/env bash
set -e
set pipefail
main {
local account="${1:?No account specified}"
# Cause script to abend if no account data stored
pass "btp/$account" > dev/null
cf login
-a "$(pass "btp/$account/cfapiendpoint")" \
-u "$(pass "btp/$account/user")" \
-p "$(pass "btp/$account/password")"
echo <<EOF
Thank you.
Logged in successfully.
EOF
}
main "$@"
Bug 1: At line 4, `pipefail` is an option that you need to set using the `-o` option of `set`.
Bug 2: At line 6, functions can be declared with the `function` keyword like this: `function main { ... }` or without the `function` keyword (as here), but parentheses are needed before the code block, like this: `main () { ... }`.
Bug 3: At line 11, `dev/null` is relative, not absolute (i.e. there's no leading `/`) so this is not really what you want (to cleanly suppress `STDOUT`, output it must be sent to `/dev/null`).
Bug 4: At line 13, the newline at the end of `cf login` is not escaped (with a `\`) so this `cf` command execution is not valid.
Bug 5: At line 18, echo does not read from STDIN so we can't use a heredoc (<<); instead, `cat` could be used (or `printf`).
Hard
#!/usr/bin/env bash
read -p 'Enter a color: ' color
if [ $color == 'black' ]; then
echo "Black is not a color, it is the absence of color"
fi
if [ $color =~ ^(red|green|blue)$ ]; then
echo "You chose a primary color"
fi
cd colors
touch "$color.txt"
Bug 4: At line 13, not checking the success (or otherwise) of a `cd` command is dangerous, and could result in the script creating, changing or deleting files in a place you didn't expect!
jq
Easy
We want a simple list of products and the categories they're in. The output should look like this:
Chai is in the Beverages category Chang is in the Beverages category Aniseed Syrup is in the Condiments category Chef Anton's Cajun Seasoning is in the Condiments category ...
The invocation of the jq script (including bugs) to produce this looks like this:
jq --raw \
'.()|"(.ProductName) is in the \(Category.CategoryName) category" \
products.json
and on its own, with extra whitespace, the (buggy) jq filter looks like this:
.()
| "(.ProductName) is in the \(Category.CategoryName) category"
Bug 2: At line 2 of the jq filter, the string interpolation construct is `\( ... )` so there's a backslash missing in the first instance (String Interpolation)
Bug 3: At line 2 of the jq filter, in the second instance of an expression being inserted into the string, the identity filter `.` is missing - it should be `.Category.CategoryName` (Identity)
The correct filter should be:
.[]|"\(.ProductName) is in the \(.Category.CategoryName) category"
Medium
We want to know how many products are still being sold, i.e. not discontinued. The answer should be a simple numeric value, like this (8 of the 77 total products in this data set are discontinued, so the value here is correct):
69
The invocation of the jq script (including bugs) to produce this looks like this:
Bug 1: At line 1 of the jq filter, the outermost element in the data set is an array, so we must use map to iterate over and call `select` (Map).
Bug 2: At line 2 of the jq filter, we're after a count of the products that are not discontinued, so we need to negate the boolean expression inside the select (Select).
The correct filter should be:
map(select(.Discontinued|not))|length
Hard
Based on the data set, we want a summary of categories with the total number of units of stock for each of those categories. The output should look like this:
Bug 1: At line 1 of the jq filter, the `group` function, which takes a path expression, is `group_by`, not `group` (Group By).
Bug 2: At line 3 of the jq filter, while `first` (which is just syntactic sugar for .[0] (Built Ins - first)) can be followed by a pipe, it can also be followed directly by the identity filter, which is missing here (should be `first.Category.CategoryName`, or `first|.Category.CategoryName` but not `first|Category.CategoryName`) (First Last Nth).
Bug 3: At line 3 of the jq filter, to use an expression as a key in a property literal, you need to wrap it in parentheses, i.e. `{(first.Category.CategoryName): ... }`, not `{first.Category.CategoryName: ...}`.
Bug 4: At line 5 of the jq filter, while `+` is valid in jq (it's an operator), it's not valid in the position it is here; the `add` filter is needed to add values in an array (Add).
Bug 5: At line 7 of the jq filter, `sum` is not a valid filter in jq, it's `add`.
Bug 1: At line 1, arrow function syntax is wrong. It should be `=>`, not `->`.
Bug 2: At line 2, variable `areThereBugs` is misspelled to `areThereBags`.
Bug 3: At line 3, There is a missing quote at the end of the string in first console.log.
Bug 4: At line 5, The `'` in `aren't` hasn't been escaped in the second console.log.
Bug 5: At line 6, There's an extra `else` that will never be called. To fix this, line 4 should either be an `else if` or the second `else` should be removed.
Medium
for (let i = 0: i < 5: i++) {
console.log(looped {i} times);
}
Bug 1: At line 1, for loop condition is using `:` instead of `;` between parameters.
Bug 2: At line 2, in the console.log statement, there are missing quotes. The correct quotes to be used are backticks `\`` for the template literal so the `i` variable is correctly updated within the string.
Bug 3: At line 2, in the console.log statement, there is a missing `$` in front of the variable curly braces `{}`.
Hard
For the last JavaScript bug hunt, "bug" identification is the name of the game. What most people call bugs or insects are actually several different classifications of the phylum arthropods.
The goal of the function in this bug hunt is to take in an object of an unidentified "bug" and determine if it is a part of the class Insecta or Arachnids, and if Insecta, further identify if it is a true bug in the order Hemiptera. To make things simple, the function should return one of the three values, "Arachnid", "Insect", or "True Bug".
Please note that some of this data might not technically be correct, entomology wise. For example, there are some arachnids with less than 8 legs. This does not count as a bug. To simplify things, the objects below are going to be used as the source of truth for arthropod classification. They should be used to determine if the function `isArachnidInsectOrBug` will return the correct output.
Hint: Keep these classification objects in mind when looking at the functions in the bug hunt.
Below are examples of potential input to the function `IsArachnidInsectOrBug`. In order to determine what is what, they need to match the values in the classification objects above. Keep in mind that all true bugs are insects but not all insects are true bugs and arachnids are neither. No coding bugs will be about the data itself being wrong.
Assume only one value in the classification object parameters with arrays will be chosen for the input object. For example, in Insect, `wingPairs` would equal either `0` or `2`, not `[0]` or `[0, 2]`. You can see this in input example 2.
Example of what could be sent into the function and expected output:
Remember, best practices is not a justification for a bug. If the code will run and output the expected result, it does not count as a bug. Also keep in mind that the point is to count the bugs, not how to fix the bugs. One fix might take care of several bugs but should not be counted as only one bug.
These are complex bugs so look carefully.
Find the bugs in the following code:
function isArachnidInsectOrBug (arthropod) {
let bugType = isInsectOrBug(arthropod);
if (!bugType) {
return isArachnid(arthropod);
}
}
function isInsectOrBug(arthropod) {
let bugType = "";
switch (arthropod.mouthType) {
case "sponging":
case "siphoning":
case "chewing":
case "piercing/sucking flexible": {
bugType = "Insect";
}
case "piercing/sucking rigid": {
bugType = "True Bug";
}
}
}
function isArachnid ({antennae, wingPairs, bodySegments, legs}) {
if (!antennae || !wingPairs || bodySegments === 2 || legs === {
return true;
}
}
Bug 1: At line 2, calling `isInsectOrBug` first will throw an error if the arthropod is an Arachnid as the arachnid object does not have the `mouthType` parameter. To fix this, call `isArachnid` first and return `Arachnid` before checking if the arthropod is an insect or true bug.
Bug 2: At line 16, in the switch statement in `isInsectOrBug`, doesn't have a break statement and will always cause `bugType` to be "True Bug".
Bug 3: At line 9, `isInsectOrBug` does not have a return statement.
Bug 4: At line 25, `isArachnid` is using the wrong boolean operators to test if arthropods is an arachnid. If any of those are correct, the function will return true. This will cause certain insects to return as Arachnid and is not correct. Bug 5: At line 27, `isArachnid` does not return anything if bug isn't an arachnid. This could cause an error as the returned value will be null. This could be handled in the `isArachnidInsectOrBug` due to truthy values but can cause unexpected errors so returning false is the best option.
Bug 6: At line 5, `isArachnidInsectOrBug` is expecting isArachnid to return the string "Arachnid" but is instead getting a boolean. This will cause isArachnidInsectOrBug to return a boolean rather than one of the three expected strings. To fix this, `isArachnidInsectOrBug` should use the value to return either "Arachnid" or further check for insect or true bug.
Bug 7: At line 5, `isArachnidInsectOrBug` will only return if bug is an arachnid. It should return the results of `isInsectOrBug` if not an empty string and otherwise throw an error if insect is none of the three expected results.
Without bugs, this is what the function could look like (without accounting for best practices and shortening code):
function isArachnidInsectOrBug (arthropod) {
let bugType = "";
if (isArachnid(arthropod)) {
bugType = "Arachnid";
} else {
bugType = isInsectOrBug(arthropod);
}
if (bugType !== "") {
return bugType;
} else {
throw new Error({
arthropod: arthropod,
err: "Arthropod is not an Arachnid, Insect, or True Bug."
})
}
}
function isInsectOrBug(arthropod) {
let bugType = "";
switch (arthropod.mouthType) {
case "sponging":
case "siphoning":
case "chewing":
case "piercing/sucking flexible": {
// Alternatively, the string could be returned here instead of using the break statement and the bugType variable.
bugType = "Insect";
break;
}
case "piercing/sucking rigid": {
bugType = "True Bug";
break;
}
}
return bugType;
}
function isArachnid ({antennae, wingPairs, bodySegments, legs}) {
// Alternatively, the result of the boolean statement in the if statement could be returned directly.
// EX. `return (!antennae && !wingPairs && bodySegments === 2 && legs === 8);`
if (!antennae && !wingPairs && bodySegments === 2 && legs === {
return true;
} else {
return false;
}
}
Bug 2: At line 2, the print statement should be indented after the function definition on line 1.
Bug 3: At line 2, The string "Hello, World!" should be wrapped in parentheses in call to `print`.
Medium
from typing import Final
#Store integers 1, 2 and 3 in variables `ONE`, `TWO`, `THREE`
ONE, TWO, THREE = range(1, 3)
ZERO : Final = 0
def check_number (x : int) -> str:
if x <= ONE:
result='smaller than or equal to 1'
elif x = TWO:
result='equal to 2'
then:
result='equal to or greater than 3'
returns result
a=input("Input the integer number: ")
print(f"{a} is {check_number(a)}")
Bug 1: At line 10, boolean operator '==' should be used instead of '='.
Bug 2: At line 12, `then` should be `else`.
Bug 3: At line 15, there is an extra `s` on `returns`. It should be `return result`.
Bug 4: At line 4, `range(1, 3)` will only provide values `1` and `2`, which is not enough values for the number of variables provided. Instead, it should be `range(1, 4)`.
Bug 5: At line 8 and 17, `<=` is not supported between instances of `str` (`a`) and `int` (`x`). To fix this, on line 17, it should be `a=int(input("Input the integer number: "))` to convert a string to an integer.
Hard
from dataclass import dataclass
class PointInTime:
year : int
month: int
day : int
point = PointInTime(1974, 12, 23)
print(point) # Output should be: PointInTime(year=1974, month=12, day=23)
Bug 1: At line 1, there is no module named 'dataclass'. Instead, it should be `from dataclasses import dataclass`.
Bug 2: At line 2, before the class `PointInTime`, there needs to be a decorator, `@dataClass` as `PointInTime()` takes no arguments without the decorator.
Wrap Up
I hope everyone had fun. Let us know in the comments if you enjoyed this and want to bring it back next year. Also feel free to share bugs you found that you were proud of or bugs you struggled with.
While Bugtoberfest might be over, Devtoberfest isn't and there's one more week of content, and another Fun Friday event left!