Open Source Development 1
References for This Lesson
Model Solutions to Exercises
These solutions are available as FOSS from
https://codeberg.org/arosano/exercises_osd0.git
OSD.0.1 - OSD.0.2
Example 1. README.md
We have not succeded in quoting markdown inside markdown
instead we refer to the live
README.
OSD.0.0 FizzBuzz
Example 2. testsuite.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
'''
testsuite.py
Copyright (c) 2025 arosano/Niels Müller Larsen
Licensed under the MIT license: https://opensource.org/license/mit
'''
import unittest
from fizzbuzz import *
class Testing(unittest.TestCase):
def test_fizz3(self):
self.assertEqual(fizzbuzz(3), 'Fizz')
def test_fizz5(self):
self.assertEqual(fizzbuzz(5), 'Buzz')
def test_fizz15(self):
self.assertEqual(fizzbuzz(15), 'FizzBuzz')
def test_fizzn(self):
self.assertEqual(fizzbuzz(31), '31')
if __name__ == '__main__':
unittest.main()
|
Example 3. fizzbuzz.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
'''
fizzbuzz.py
Copyright (c) 2025 arosano/Niels Müller Larsen
Licensed under the MIT license: https://opensource.org/license/mit
'''
def fizzbuzz(n):
s = ''
if n % 3 == 0:
s += 'Fizz'
if n % 5 == 0:
s += 'Buzz'
if s == '':
s = f'{n}'
return s
if __name__ == '__main__':
for i in range (1, 101):
print(fizzbuzz(i))
|
To be tested by
Example 4. Running the Test
1
2
3
4
5
6
7
8
9
10
|
$ python testsuite.py -v
test_fizz15 (__main__.Testing.test_fizz15) ... ok
test_fizz3 (__main__.Testing.test_fizz3) ... ok
test_fizz5 (__main__.Testing.test_fizz5) ... ok
test_fizzn (__main__.Testing.test_fizzn) ... ok
----------------------------------------------------------------------
Ran 4 tests in 0.000s
OK
|
Example 5. Running the Program
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
$ python fizzbuzz.py
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
....
94
Buzz
Fizz
97
98
Fizz
Buzz
|
OSD.0.1 Palindromy
Example 6. testsuite.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
'''
testsuite.py
Copyright (c) 2025 arosano/Niels Müller Larsen
Licensed under the MIT license: https://opensource.org/license/mit
'''
import unittest
from palindromy import *
class Testing(unittest.TestCase):
def test_isPal1(self):
self.assertFalse(isPalindrome('Fizz'))
def test_isPal2(self):
self.assertFalse(isPalindrome('1234'))
def test_isPal3(self):
self.assertTrue(isPalindrome('regninger'))
def test_isPal4(self):
self.assertTrue(isPalindrome('RegninGer'))
def test_isPal5(self):
self.assertTrue(isPalindrome('A man, a plan, a canal - Panama'))
if __name__ == '__main__':
unittest.main()
|
Example 7. palindromy.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
'''
palindromy.py
Copyright (c) 2025 arosano/Niels Müller Larsen
Licensed under the MIT license: https://opensource.org/license/mit
'''
import re
import sys
def isPalindrome(txt):
if len(txt) <= 1:
return True
txt = txt.lower()
txt = re.sub(r'[^\w]', '', txt)
return txt[0] == txt[-1] and isPalindrome(txt[1:-1])
if __name__ == '__main__':
print(f'Is "{sys.argv[1]}" a palindrome? {isPalindrome(sys.argv[1])}!')
|
Example 8. Running the Testsuite
1
2
3
4
5
6
7
8
9
10
11
|
$ python testsuite.py -v
test_isPal1 (__main__.Testing.test_isPal1) ... ok
test_isPal2 (__main__.Testing.test_isPal2) ... ok
test_isPal3 (__main__.Testing.test_isPal3) ... ok
test_isPal4 (__main__.Testing.test_isPal4) ... ok
test_isPal5 (__main__.Testing.test_isPal5) ... ok
----------------------------------------------------------------------
Ran 5 tests in 0.001s
OK
|
Example 9. Running the Program
1
2
3
4
|
$ python palindromy.py 'Trials and Tirbulations'
Is Trials and Tirbulations a palindrome? False!
$ python palindromy.py 'Dennis and Edna sinned'
Is Dennis and Edna sinned a palindrome? True!
|
OSD.0.2 Primality
The solution to this exercise is made in JavaScript
for the versatility.
Example 10. test-suite.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
/*
test-suite.js -- tests for primes
Copyright (c) Niels Müller Larsen
Licensed under the MIT license: https://opensource.org/license/mit
*/
const test = require('node:test'); // new in node as of V18
const assert = require('assert/strict');
const { // the functions to be tested
isPrime,
isPrimeArchaic,
isPrimeWell
} = require('./mathlib');
// test synch
test('sync 25', function() {
return assert.equal(isPrime(25), false);
});
// test synch
test('sync 257', function() {
return assert.ok(isPrime(257));
});
// test synch
test('sync 9007199254740991', function() {
return assert.equal(isPrime(9007199254740991), false);
});
// test synch
test('sync 9007195909437503', function() {
return assert.equal(isPrime(9007195909437503), false);
});
// tests asynch
test('async small no', async function(t) {
await t.test('async 257', function() {
assert.ok(isPrime(257));
});
});
// test synch
test('sync 256', function() {
return assert.equal(isPrime(256), false);
});
// test alternative isPrime functions
// test synch
test('sync archaic 257', function() {
return assert.ok(isPrimeArchaic(257));
});
// test synch
test('sync hm 257', function() {
return assert.ok(isPrimeWell(257));
});
|
Example 11. mathlib.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
/*
mathlib.js
various math related functions
Copyright (c) Niels Müller Larsen
Licensed under the MIT license: https://opensource.org/license/mit
*/
module.exports = {
isPrime: function (n) {
if (n % 2 === 0 || n % 3 === 0)
return false;
const limit = Math.sqrt(n);
const magic = 6;
let i = 1;
let divm1 = magic * i - 1;
let divp1 = magic * i + 1;
while (divm1 <= limit || divp1 <= limit) {
if (n % divm1 === 0 || n % divp1 === 0)
return false;
i++;
divm1 = magic * i - 1;
divp1 = magic * i + 1;
}
return true;
},
isPrimeArchaic: function (n) {
if (n % 2 === 0)
return false;
for (let i = 3; i <= Math.sqrt(n); i += 2)
if (n % i === 0)
return false;
return true;
},
isPrimeWell: function(n) {
for (let i = 2; i < n; i++)
if (n % i === 0)
return false;
return true;
}
}
|
Example 12. primes.js
1
2
3
4
5
6
7
8
|
const lib = require('./mathlib')
const doSomething = function (n) {
return lib.isPrime(n);
};
let candidate = process.argv[2];
console.log(`Is ${candidate} prime: ${doSomething(candidate)}`);
|
Example 13. Running the Testsuite
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
$ node --test
✔ sync 25 (1.884537ms)
✔ sync 257 (0.246666ms)
✔ sync 9007199254740991 (0.320865ms)
✔ sync 9007195909437503 (303.511543ms)
▶ async small no
✔ async 257 (0.3208ms)
▶ async small no (0.726882ms)
✔ sync 256 (0.226422ms)
✔ sync archaic 257 (0.224919ms)
✔ sync hm 257 (0.341712ms)
ℹ tests 9
ℹ suites 0
ℹ pass 9
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 410.47722
|
Example 14. Running the Program
1
2
3
4
5
6
7
8
|
$ node prog_osd02.js 157
Is 157 prime: true
$ node prog_osd02.js 257
Is 257 prime: true
$ node prog_osd02.js 9007199254740991 // 6361 * 69431 * 20394401
Is 9007199254740991 prime: false
$ node prog_osd02.js 9007195909437503 // 94906249 * 94906247
Is 9007195909437503 prime: false // (15817708*6-1) * (15817708*6+1)
|
From the Previous Lesson
Some words about
use cases,
in particular the diagrams.
Some Flashbacks Before the Exercises
This is from the most recent lesson.
Important to remember when writing tests.
SitePoint
advocates what they call the AAA pattern.
The Arrange, Act and Assert pattern is a common strategy used to
write and organize unit tests. It works in the following way:
- During the Arrange phase, all the objects and variables
needed for the test are set.
- Next, during the Act phase, the function/method/class
under test is called.
- In the end, during the Assert phase,
we verify the outcome of the test.
This strategy provides a clean approach to organizing unit tests
by separating all the main parts of a test: setup, execution
and verification. Plus, unit tests are easier to read, because
they all follow the same structure.
Coding Memories
Example 15. Creating a Class in JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
/*
* Student.js
*
* Copyright (c) 2025, Niels Müller Larsen
* Licensed under the MIT license: https://opensource.org/license/mit
*/
module.exports = class Student {
constructor(first, last, city, country) {
if (!
(typeof(first) == 'string'
&& typeof(last) === 'string'
&& typeof(city) === 'string'
&& typeof(country) === 'string'
)
) {
return false;
}
this.first = first;
this.last = last;
this.city = city;
this.country = country;
}
}
|
Example 16. Using a Class in JavaScript
1
2
3
4
5
6
7
8
9
|
const Stu = require('./Student.js');
let a = 'Niels';
let b = 'Larsen';
let c = 'Aarhus';
let d = 'Denmark';
let s = new Stu(a, b, c, d);
console.log(`Student ${s.first} is from ${s.city}, ${s.country}`);
|
Example 17. Creating a Class in Python
1
2
3
4
5
6
7
8
9
10
11
12
13
|
'''
Student.py
Copyright (c) 2025, Niels Müller Larsen
Licensed under the MIT license: https://opensource.org/license/mit
'''
class Student:
def __init__(self, first, last, city, country):
self.first = first
self.last = last
self.city = city
self.country = country
|
Example n. Using a Class in Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
'''
test.py
'''
from Student import Student
first = 'Niels'
last = 'Larsen'
city = 'Aarhus'
ctry = 'Denmark'
s = Student(first, last, city, ctry)
print(s)
print(f'Student {s.first} is from {s.city}, {s.country}')
|
Exercises
The rules for handing in assignments may be found in the README
Todays submissions MUST be in a repo called
exercises_osd1
. You MAY solve them in Python or
JavaScript.
Exercise OSD.1.0
Given the following specification, first write
a testsuite
containing tests
for the methods of the class that fulfill the
specification below.
Then write a program that demonstrates the results.
Remember to test frequently.
The tests help you.
Create a class Rational
.
The constructor should have two properties:
a numerator, and a denominator. Both MUST
be integers.
The constructor may take zero, one or two
arguments.
- With zero arguments the numerator must
default to 0, and the denominator to
1.
- With one argument, the numerator
must take the value of the argument, and
the denominator must be 1.
- With two arguments, the denominator must
take the value of the first argument, and
the denominator must take the value of
the second argument.
The class MUST contain the following
methods:
reduce()
- This method must reduce the fraction as much as possible
gcd(a,b)
- For the
reduce
I will give you the following
implementation of Euclid’s algorithm:
const gcd = function (a, b) {
if (b == 0) {
return a;
} else {
return gcd(b, a % b);
}i
}
This must be a static method.
negate()
- This method must change the sign of the fraction.
invert()
- This method must swap numerator and denominator.
cmp(rational)
- This take another object of the class Rational
as input. Then it compares the value of the
object with that of the input fraction.
It must return
-1
if the value af the instance
is smaller, 0
if they are equal, and +1
if the value of the instance is greater than
that of the input fraction.
toString()
- Returns a string representation af the
fraction eg
3/7
. If the value is 0
,
0
must be returned, if the value is
an integer, the integer, eg 7
, must
be returned.
add(rational)
- Adds the value of the input fraction to that
of the instance.
sub(rational)
- Subtracts the value of the input fraction form
that of the instance.
mul(rational)
- Multiplies the value of the input fraction with
that of the instance.
div(rational)
- Divides the value of the input fraction into
that of the instance.