Complete unit test - python

i have a question
Write a program to check the validity of password input by users.
Following are the criteria for checking the password:
At least 1 letter between [a-z]
At least 1 number between [0-9]
At least 1 letter between [A-Z]
At least 1 character from [$##]
Minimum length of transaction password: 6
Maximum length of transaction password: 12
Your program should accept a sequence of comma separated passwords and will
check them according to the above criteria. Passwords that match the criteria are
to be printed, each separated by a comma
Example
If the following passwords are given as input to the program:
ABd1234#1,a F1#,2w3E*,2We3345
Then, the output of the program should be:
ABd1234#1
the solution is below
def check_password(word):
special_str = "$##"
accepted = []
passwords = word.split(',')
for password in passwords:
lower = 0
upper = 0
digits = 0
special = 0
for char in password:
if char.islower():
lower += 1
elif char.isupper():
upper += 1
elif char.isdigit():
digits += 1
elif special_str.find(char) != -1:
special += 1
if lower >= 1 and upper >= 1 and digits >= 1 and special >= 1 and len(password) in range(6,13):
accepted.append(password)
return accepted
i was told to also write a unit test for it
Now am new to using unit tests, so after going through some examples i tried writing a unit test as below
import unittest
import question1
class Test_PasswordChecker(unittest.TestCase):
def test_valid(self):
self.assertEquals(question1.check_password("ABd1234#1,a F1#,2w3E*,2We3345"),'ABd1234#1')
if __name__ == '__name__':
unittest.main()
The source code works well, though am having problems on whether i have made the correct unit test for it.
Need some help on how to make the best unit test

First of all your code has an issue: you are printing the result instead of returning it.
As a general principle you should always strive to decouple input-ouput to "processing". If you have functions that both compute stuff and print/request input you end up reducing their reusability and testability.
In this case the issue with your unittest is that check_password always returns None since you did not return anythign and hence it will always fail.
So first thing replace:
print(accepted)
with
return accepted
Now: you need more than one test for this function. You should try to write a test for all possible cases.
For example:
check what happens when no password satisfies the requirements?
What happens if all satisfy the requirements?
What happens if you give the empty input to the function?
For each requirement try to see what happens if you try to call the function with a password that satisfies all requirement except that one.(e.g. a password that has a lowercase letter, an uppercase letter, a symbol, a digit but whose length is 4 or 20).
Basically you should try to divide the possible input into a number of categories and check at least one input for each category.

Related

How to suppress output in python without using characters and spaces?

I found out I can solve this problem in a better space complexity if I enter inputs one at time. However, python is defeating the purpose of my script.
Because python is outputting O(n) elements that I just gave for input.
0
2
no
See that 0 and 2 for inputs? I only need one line. And it can only have the current input for that one particular line. (not 0,2....) Otherwise, the computer is technically still using O(n) space just for the graphics card to remember what pixels to output.
I tried using os.devnull and other methods. But, the computer still used O(N) space by simply outputting none or null. Outputting space characters still use O(N) space so does every other possible character you can think of. Output must be 100% suppressed excluding the yes or no outputs.
This isn't impossible because I guarantee you that the algorithm works by hand with an auxiliary space better than O(N)
# Decision Problem: Is N in index M?
import sys
import os
M = 2
N = 2
index = -1
while True:
# We are going to enter each element from our list ONE AT A TIME.
# This will improve our space-complexity that is better than O(n)
# Be careful not to enter the elements out of order.
a = int(input(os.devnull))
index = index + 1
if a == N:
if index == M:
print('yes')
break
if index > M:
print('no')
break
if index < M:
if a == N:
print('no')
break
Question
How do I suppress output completely without losing my "yes" or "no" outputs?

Python unit test fails despite meeting requirement

I am doing an online python course that requires I complete some exercise to progress. The orginisers of this course says they have visible and hidden requirements a user must meet pass each test. In this case, the probelem statement is as follows:
Write a function called manipulate_data which will act as follows:
When given a list of integers, return a list, where the first element is the count of positives numbers and the second element is the sum of negative numbers.
NB: Treat 0 as positive.
I came up with this, which I believe passes the visible requirement except maybe line 6 of the unit test case
def manipulate_data(listinput):
report = [0,0]
if type(listinput) != list:
#I may need some work here.. see unit test line 6
assert "invalid argument"
for digit in listinput:
#is an even number so we increment it by 1
if digit >= 0 and type(digit) == int:
report[0] += 1
#number is less than zero, adds it sum
elif digit < 0 and type(digit) == int:
report[1] += digit
return report
EveryTime I run the code, I always get this Error message Indicating that my code passes 2 test out of three, which I assume is test_only_list_allowed(self) I am not really experienced with this kind of things and I need help.
The test shows that the code expected a string to be returned. assert raises an AssertionError exception instead. You want to return the same string as the assertEquals() test is looking for, so 'Only lists allowed', not the msg argument (which is shown when the test fails).
Instead of using assert use return, and return the expected string:
if type(listinput) != list:
return "Only lists allowed"
Note that normally you'd use isinstance() to test for types:
if not isinstance(listinput, list):
return "Only lists allowed"
for digit in listinput:
if not isinstance(digit, int):
continue
if digit >= 0:
report[0] += 1
elif digit < 0:
report[1] += digit
I used a single test for integers instead of testing in each branch. You could even have a type that doesn't support comparison with 0 so you want to get that test out of the way first.

String processing - Determine if parenthesis are balanced

I am working with the code that would read the input of the strings and compute whether the parenthesis (using arbitrary characters for open and close) are balanced. The aim is to prompt user to input the amount of brackets as strings, so the compiler would compute their amount and type(ex. if it is '(' or ')') .
I have been given hints:
Hint1: introduce two counters initialized to zero in the beginning.
Then explore the symbols of the string in a loop. For the current
symbol increment the left counter by 1 if the symbol is '(',
otherwise, increment by 1 the `right' counter
Hint2: call a string math-like if the brackets occur like in a
mathematical formula. For instance, the strings '()', '(())()',
'(()())' are balanced, while the strings '))(())((' and '())(()'
are not.
My code now looks like this:
lefts =str(input("Please enter a left parenthesis: "))
rights =str(input("Please enter a right parenthesis: "))
#token parsing requires paying attention to the order of the parenthesis
def ptest(test): #testing with counters
lefts = 0
rights = 0
balance = 0 #additional counter that will help us determine the amount of strings and their relation to each other
for c in test:
if c == '(':
balance += 1
lefts += 1
elif c == ')':
balance -= 1
rights += 1
print ('testing "'+test+'"')
print ('lefts='+str(lefts)+' rights='+str(rights))
#if there will b a balance between the strings/parenthesis, they will possibly be balanced
if balance == 0: print 'same number of open/close, possibly balanced'
else: print 'different number of open/close, definitely not balanced'
ptest(test1)
ptest(test2)
How could I modify this in order that it would work?
But I think you partly misunderstood the task.
There can be many brackets, but no more ")" than "(" (and at the end the number of both types must be equal)
And I would think, that the input not only consists of brackets
So you should build a loop (as you did) and
test, whether the char is a bracket or not
if a bracket, so increase the matching counter (you could even have one Counter, but it is easier to understand with two of them
Check, whether the closing Counter is smaller than the opening (if not, so you could break the Loop, cause it is not mathematical)
After the end of the loop you must check, whether there were an error in the Loop or both Counters are not equal. In both cases the string is not "mathematical", otherwise it is.
I could do it in your code, but I think, you should do THIS alone. Most of These things you have already done, but it seems as you did not completly understand, what you have done and have to do.

How to limit the amount of numbers given in a float input? (Python)

Novice Pythoner here. I am trying to finish my first program (a tip calculator) and I have one last piece of code to write. Here is the part of code I need to add on to:
bill_amt = True
while bill_amt:
try:
bill_amt = float(input('First, what was the price of your meal?:'))
except:
print('Please enter a number only.')
continue
if bill_amt <= 0:
print('Your meal wasn\'t $',bill_amt,'! Please try again.')
bill_amt = True
else:
x = float(bill_amt)
bill_amt = False
What I want to do is add a command that will limit the amount of numbers you can input when the code asks how much your meal was so user can't type in 4511511513545513513518451.32. I've tried using len(bill_amt) > 8, but I get an error that floats don't have strings. How do I get around this? Thanks, sorry if it's a duplicate! -Pottsy
use regex matching, this will also prevent the user from typing in something like "12.123456"
import re
# ...
while True:
inp = input('First, what was the price of your meal?:'))
if bool(re.match(r"^\d{1,8}\.\d\d$", inp)):
return float(inp)
else:
print('invalid entry')
\d means digit, {1,8} means allow anywhere from 1 to 8 digits. \d\d looks for two digits after the ., so this regex will match 1-8 digits, followed by a dot, followed by two more digits.
Note that if you are dealing with money, you don't generally want to use floats, but rather decimal.Decimals. Try doing
decimal.Decimal(inp)
at the end instead.
In order to get the length use str(bill_amount)
len(str(123.53)) is 6
Note that even though Python will allow you to use a float value and then change it to the boolean, it would be better to make it a different name rather than have both the float and the boolean as bill_amt
.
Float doesn't have length but str does:
bill_amt_str = input('First, what was the price of your meal?:')
if len(bill_amt_str.replace(".", "")) > 8:
print("No more than 8 digits please.")
continue
bill_amt = float(bill_amt_str)

Replacing in Python

I need to complete a basic task on Python that requires me to convert a standard phone number into an international one.
So for example, if the users phone number was 0123456789, the program should display, Your international phone number is +44123456789.
I don't know how to replace the 0 with a 44. I don't know many techniques on Python so advice on how to is welcomed, thanks.
EDIT:
#Python Number Conversion
def GetInternational(PhoneNumber):
if num.startswith('0'):
num = num.replace('0','+44',1)
return GetInternational
PhoneNumber = input("Enter your phone number: ")
print('Your international number is',GetInternational,'')
I'm missing something obvious but not sure what...
Another way to do it would be:
num.replace('0','+44',1) #Only one, the leftmost zero is replaced
Therefore if the number starts with zero we replace only that one,
num = "0123456789"
if num.startswith('0'):
num = num.replace('0','+44',1)
Well the simplest way to do it is strip off the first character (the 0) and then concatenate it with +"44":
num = "0123456789"
if num.startswith("0"):
num = "+44" + num[1:]
For clarity I added a startswith check to make sure the substitution only happens if the number starts with a zero.

Categories