Skip to content

Instantly share code, notes, and snippets.

@yangwansu
Last active August 29, 2015 13:57
Show Gist options
  • Save yangwansu/9679634 to your computer and use it in GitHub Desktop.
Save yangwansu/9679634 to your computer and use it in GitHub Desktop.
신용카드번호 검증 LUHN 알고리즘 TDD 로 구현
package org.slipp.study.tdd.luhn;
import org.apache.commons.lang.ArrayUtils;
//LUHN
public class CardNumber {
private final Integer[] numbers;
private final Integer checksum;
private final String cardNumberString;
public CardNumber(String cardNumberString) {
this.cardNumberString = cardNumberString;
this.numbers = convertArray() ;
this.checksum = numbers[numbers.length - 1];
}
Integer[] getTargets() {
Integer[] sub = (Integer[]) ArrayUtils.subarray(ArrayUtils.clone(numbers), 0, numbers.length-1);
ArrayUtils.reverse(sub);
return sub;
}
Integer[] convertArray() {
Integer[] array = new Integer[cardNumberString.length()];
for(int i=0;i<cardNumberString.length();++i){
array[i]=Integer.parseInt(cardNumberString.charAt(i)+"");
}
return array;
}
int checksum() {
return checksum;
}
int sumvalue() {
int sum=0;
Integer[] targets = getTargets();
for(int i=0;i <targets.length;i++){
int current = targets[i];
if(0 == i%2){
int doubles = (current*2);
//System.out.println(current+ "X2 = "+doubles+" : ("+ (doubles % 10) +" "+ (doubles / 10)+")");
sum = sum + (doubles % 10) + (doubles / 10);
}else{
//System.out.println(current);
sum = sum + current;
}
}
return sum;
}
static Integer nextTenNumber(int i) {
return 10*((i/10)+1);
}
Integer calculate() {
return nextTenNumber(sumvalue()) - sumvalue();
}
public Boolean isValid() {
return checksum() == calculate();
}
}
package org.slipp.study.tdd.luhn;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import org.junit.Test;
public class LUHNTest {
/*
*
* 신용 카드상의 번호 검증을 위해 사용하는 알고리듬. 1960년대에 개발된 개방형 공식이다.
* 원리는
* ㉠ 카드 번호의 우측 숫자부터 매 2번째 숫자마다 2를 곱하고,
* ㉡ 위 ㉠에서 2를 곱하지 않은 숫자들 중 가장 우측 수를 제외하고 (이 수는 추후 점검수로 쓰인다.) ㉠에서 나온 숫자들을 합한다
* (㉠에서 나온 수가 2자리 수이면 2개의 숫자를 합한다).
*
* ㉢ 위 ㉡에서 나온 수와 그 다음으로 큰 10단위 수와의 차이를 구한다(㉡에서 나온 수가 34이면 다음으로 큰 10단위 수 40과의 차이, 6을 구한다).
* ㉢에서 나온 숫자가 카드의 점검 숫자와 일치해야 한다.
*
* */
/*
카드번호 1234567890 은 유효하지 않은 카드 번호이다.(이하 넘버A )
DONE 넘버A의 점검수(checksum)는 0 이다.
DONE 맨오른쪽수는_점검수이다.
DONE 넘버A의 ㄱ 계산값(sumvalue)는 43 이다.
DONE 넘버A의 ㄱ 계산값 의 다음 큰 10단위 수는 50 이다.
DONE 넘버A의 ㄷ 결과 값은 7 이다.
DONE CardNumber 생성자에 널 값 또는 빈 값 또는 숫자가 아닌 경우
*/
String 진짜신용카드번호 = "9436457659365131";
String 잘못된카드번호 = "1234567890";
@Test
public void 맨오른쪽수는_점검수이다() throws Exception{
assertThat(new CardNumber(잘못된카드번호).checksum(), is(0));
assertThat(new CardNumber("123456789").checksum(), is(9));
assertThat(new CardNumber("12345678").checksum(), is(8));
assertThat(new CardNumber(진짜신용카드번호).checksum(), is(1));
}
@Test
public void sumvalue() throws Exception{
assertThat(new CardNumber(잘못된카드번호).sumvalue(), is(43));
assertThat(new CardNumber("0").sumvalue(), is(0));
assertThat(new CardNumber("10").sumvalue(), is(2));
assertThat(new CardNumber("210").sumvalue(), is(4));
assertThat(new CardNumber("3210").sumvalue(), is(10));
assertThat(new CardNumber(진짜신용카드번호).sumvalue(), is(79));
}
@Test
public void getTargets() throws Exception{
assertString(new CardNumber("0").getTargets(), "");
assertString(new CardNumber("90").getTargets(), "9");
assertString(new CardNumber("890").getTargets(), "98");
assertString(new CardNumber(잘못된카드번호).getTargets(), "987654321");
}
private void assertString(Integer[] actual, String expected) {
String ret = "";
for (Integer each : actual) {
ret=ret+each;
}
assertThat(ret,is(expected));
}
@Test
public void 다음10단위구하기() throws Exception{
assertThat(CardNumber.nextTenNumber(0),is(10));
assertThat(CardNumber.nextTenNumber(1),is(10));
assertThat(CardNumber.nextTenNumber(9),is(10));
assertThat(CardNumber.nextTenNumber(10),is(20));
assertThat(CardNumber.nextTenNumber(11),is(20));
assertThat(CardNumber.nextTenNumber(19),is(20));
assertThat(CardNumber.nextTenNumber(20),is(30));
assertThat(CardNumber.nextTenNumber(43),is(50));
}
@Test
public void 최종결과() throws Exception{
assertThat(new CardNumber(잘못된카드번호).calculate(), is(7));
assertThat(new CardNumber(진짜신용카드번호).calculate(), is(1));
}
@Test
public void 유효체크() throws Exception{
assertThat(new CardNumber(잘못된카드번호).isValid(), is(false));
assertThat(new CardNumber(진짜신용카드번호).isValid(), is(true));
}
}
@yangwansu
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment