Skip to content

Instantly share code, notes, and snippets.

@aerphanas
Last active December 15, 2023 09:25
Show Gist options
  • Select an option

  • Save aerphanas/5307ed968312ef23c7cb7c4cb39c2cc2 to your computer and use it in GitHub Desktop.

Select an option

Save aerphanas/5307ed968312ef23c7cb7c4cb39c2cc2 to your computer and use it in GitHub Desktop.
Group 1
# Any copyright is dedicated to the Public Domain.
# https://creativecommons.org/publicdomain/zero/1.0/
# Author : Muhammad Aviv Burhanudin
def atop(f, g):
"""Fungsi komposisi (B Combinator)"""
def go(x):
return f(g(x))
return go
def identity(x):
"""Fungsi yang mengembalikan argumenya (I Combinator)"""
return x
def interupt_input(msg):
"""Fungsi untuk menangani input
Mengembalikan None jika gagal
Seperti fungsi input biasa namun
fungsi ini menangani pembatalan input
saat kita memberikan sinyal SIGINT atau
CTRL + c
"""
try:
return input(msg)
except KeyboardInterrupt:
print("\nMembatalkan Program.")
return None
def int_input(msg):
"""Fungsi untuk menangani input
Mengembalikan None jika gagal
Validasi input yang hanya menerima
bilangan bulat
"""
try:
ip = interupt_input("{}".format(msg))
if ip is None:
return None
else:
return atop(int, identity)(ip)
except ValueError:
print("Input harus berupa bilangan bulat. Coba lagi.")
return int_input(msg)
def safe_int_input(itm_chk):
"""Fungsi yang mengecek angka input"""
while True:
nomor = int_input("Masukan nomor: ")
if nomor is None:
return None
elif nomor > len(itm_chk) or nomor < 1:
print("Masukan angaka dengan benar")
return safe_int_input(itm_chk)
else:
return nomor
def print_separator():
"""Menampilkan separator --- di terminal"""
separator = "-" * 40
return print(separator)
def p_double_newline():
"""Menampilkan 2 new line di terminal"""
newlines = "\n\n"
return print(newlines)
def pprint_judul(judul):
"""Menampilkan judul dengan style yang sudah ditetapkan"""
styled_judul = "< {} >".format(judul).center(40, "=")
return print(styled_judul)
def print_menu():
"""Menampilkan menu aplikas ke terminal"""
pprint_judul("Menu")
print("1. Tampilkan Semua Novel")
print("2. Tampilkan Novel dengan Genre")
print("3. Tambah Novel")
print("4. Hapus Novel")
print("5. Update Novel")
print("6. Keluar")
print_separator()
def l_iota(lst):
"""Mengembalikan iota dari list"""
return atop(range, len)(lst)
def red_novel(database_novel):
"""Menampilkan semua novel di database_novel"""
pprint_judul("List Novel")
for n in l_iota(database_novel):
nomor = n + 1
judul = database_novel[n][0]
genre = database_novel[n][1]
print("{}. {} - {}".format(nomor, judul, genre))
def search_novel_genre(database_novel, genre):
"""Menampilkan novel dengan genre yang ditetapkan"""
pprint_judul("list novel dengan genre {}".format(genre))
nama_novel = []
for novel in database_novel:
if genre in novel:
nama_novel.append(novel[0])
if len(nama_novel) == 0:
print("(!) Tidak ada genre {} dalam database".format(genre))
else:
for i in l_iota(nama_novel):
print("{} - {}".format(i + 1, nama_novel[i]))
def red_novel_genre(database_novel, nomor, genre):
"""Menampilkan novel dengan nomor genre"""
genre_name = genre[nomor - 1]
return search_novel_genre(database_novel, genre_name)
def red_genre(genre):
"""Menampilkan semua genre"""
pprint_judul("List Genre")
for n in l_iota(genre):
nomor = n + 1
nama_genre = genre[n]
print("{}. {}".format(nomor, nama_genre))
def add_novel(database_novel, title, genre):
"""Menambahkan novel"""
novel = [title, genre]
return database_novel.append(novel)
def del_novel(database_novel, nomor):
"""Menghapus novel dengan nomor index"""
index = nomor - 1
return database_novel.pop(index)
def update_genre(database_novel):
"""Mengembalikan Genre list tanpa dulpikasi"""
genre = []
for g in database_novel:
if g[1] not in genre:
genre.append(g[1])
return genre
def main():
"""Main Event Loop"""
# dummy list for demonstration
# database_novel = [
# [ "Haskell Books" , "Functional" ],
# [ "Lambda Lisp" , "Lisp" ],
# [ "Lisp for web" , "Website" ],
# [ "Clojure for Brave" , "Lisp" ],
# [ "Python Soyjak" , "Programming" ]
# ^ ^
# Judul Novel Genre
# ]
database_novel = []
while True:
p_double_newline()
print_menu()
pilih = int_input("Pilih [1-6]: ")
if pilih is None:
break
p_double_newline()
if pilih == 1:
# Tampilkan Semua Novel
if len(database_novel) == 0:
print("Database kosong, tolong tambahkan novel")
continue
red_novel(database_novel)
elif pilih == 2:
# Tampilkan Novel dengan Genre
if len(database_novel) == 0:
print("Database kosong, tolong tambahkan novel")
continue
genre = update_genre(database_novel)
atop(red_genre, identity)(genre)
nomor = safe_int_input(database_novel)
if nomor is None:
break
p_double_newline()
red_novel_genre(database_novel, nomor, genre)
elif pilih == 3:
# Tambah Novel
title = interupt_input("Masukan Judul Novel: ")
if title is None:
break
genre = interupt_input("Masukan Genre: ")
if title is None:
break
add_novel(database_novel, title, genre)
elif pilih == 4:
# Hapus Novel
if len(database_novel) == 0:
print("Database kosong, tolong tambahkan novel")
continue
red_novel(database_novel)
nomor = safe_int_input(database_novel)
if nomor is None:
break
del_novel(database_novel, nomor)
elif pilih == 5:
# Update Novel
if len(database_novel) == 0:
print("Database kosong, tolong tambahkan novel")
continue
red_novel(database_novel)
nomor = safe_int_input(database_novel)
if nomor is None:
break
title = interupt_input("Masukan Judul Baru: ")
if title is None:
break
genre = interupt_input("Masukan Genre Baru: ")
if genre is None:
break
del_novel(database_novel, nomor)
add_novel(database_novel, title, genre)
elif pilih == 6:
# keluar
print("Terimakasih sudah menggunakan aplikasi ini, Bye")
break
else:
print("Tolong masukan input dengan benar")
continue
if __name__ == "__main__":
main()
# Any copyright is dedicated to the Public Domain.
# https://creativecommons.org/publicdomain/zero/1.0/
# Author : Muhammad Aviv Burhanudin
import unittest
from unittest.mock import patch
from kerkom import (
interupt_input,
int_input,
safe_int_input,
pprint_judul,
red_novel,
red_novel_genre,
red_genre,
add_novel,
del_novel,
update_genre,
)
class DatabaseNovel():
database_novel = [
[ "Haskell Novels" , "Functional" ],
[ "Lambda Lisp" , "Lisp" ],
[ "Lisp for web" , "Website" ],
[ "Clojure for Brave" , "Lisp" ],
[ "Python Soyjak" , "Programming" ]
]
genre = [
"Functional",
"Lisp",
"Website",
"Programming"
]
class TestKerkomInput(unittest.TestCase, DatabaseNovel):
@patch('builtins.input', return_value='Test Input')
def test_interrupt_input(self, mock_input):
result = interupt_input("Enter something: ")
self.assertEqual(result, 'Test Input')
@patch('builtins.input', return_value='42')
def test_int_input(self, mock_input):
result = int_input("Enter an integer: ")
self.assertEqual(result, 42)
@patch('builtins.input', return_value='2')
def test_safe_int_input(self, moce_input):
test_db = DatabaseNovel.database_novel.copy()
result = safe_int_input(test_db)
self.assertEqual(result, 2)
class TestPrintFunction(unittest.TestCase):
@patch('builtins.print')
def test_pprint_judul(self, mock_print):
pprint_judul("List Novel")
expected_calls = "=============< List Novel >============="
actual_calls = [
call[0]
for call in mock_print.call_args_list
][0][0]
self.assertEqual(actual_calls, expected_calls)
@patch('builtins.print')
def test_red_novel(self, mock_print):
red_novel(DatabaseNovel.database_novel)
expected_calls = [
"=============< List Novel >=============",
"1. Haskell Novels - Functional",
"2. Lambda Lisp - Lisp",
"3. Lisp for web - Website",
"4. Clojure for Brave - Lisp",
"5. Python Soyjak - Programming"
]
actual_calls = [
call[0][0]
for call in mock_print.call_args_list
]
self.assertEqual(actual_calls, expected_calls)
@patch('builtins.print')
def test_red_novel_genre(self, mock_print):
red_novel_genre(DatabaseNovel.database_novel,
2, # Lisp
DatabaseNovel.genre)
expected_calls = [
"====< list novel dengan genre Lisp >====",
"1 - Lambda Lisp",
"2 - Clojure for Brave"
]
actual_calls = [
call[0][0]
for call in mock_print.call_args_list
]
self.assertEqual(actual_calls, expected_calls)
@patch('builtins.print')
def test_red_genre(self, mock_print):
red_genre(DatabaseNovel.genre)
expected_calls = [
"=============< List Genre >=============",
"1. Functional",
"2. Lisp",
"3. Website",
"4. Programming",
]
actual_calls = [
call[0][0]
for call in mock_print.call_args_list
]
self.assertEqual(actual_calls, expected_calls)
class TestSideEffectFunction(unittest.TestCase, DatabaseNovel):
def test_add_novel(self):
test_db = DatabaseNovel.database_novel.copy()
add_novel(test_db,
"test",
"test")
expected_result = [
[ "Haskell Novels" , "Functional" ],
[ "Lambda Lisp" , "Lisp" ],
[ "Lisp for web" , "Website" ],
[ "Clojure for Brave" , "Lisp" ],
[ "Python Soyjak" , "Programming" ],
[ "test" , "test" ]
]
self.assertEqual(test_db, expected_result)
def test_del_novel(self):
test_db = DatabaseNovel.database_novel.copy()
del_novel(test_db, 5)
expected_result = [
[ "Haskell Novels" , "Functional" ],
[ "Lambda Lisp" , "Lisp" ],
[ "Lisp for web" , "Website" ],
[ "Clojure for Brave" , "Lisp" ]
]
self.assertEqual(test_db, expected_result)
def test_update_genre(self):
test_db = DatabaseNovel.database_novel.copy()
result = update_genre(test_db)
expected_result = [
"Lisp",
"Programming",
"Functional",
"Website"
]
for el in result:
self.assertTrue(el in expected_result)
if __name__ == "__main__":
unittest.main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment