package com.lochbridge.oath.otp.keyprovisioning.qrcode; import static org.junit.Assert.assertEquals; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.attribute.FileAttribute; import java.util.Hashtable; import java.util.Map; import java.util.concurrent.TimeUnit; import javax.imageio.ImageIO; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import com.google.common.io.BaseEncoding; import com.google.zxing.BinaryBitmap; import com.google.zxing.DecodeHintType; import com.google.zxing.MultiFormatReader; import com.google.zxing.NotFoundException; import com.google.zxing.Result; import com.google.zxing.client.j2se.BufferedImageLuminanceSource; import com.google.zxing.common.HybridBinarizer; import com.lochbridge.oath.otp.keyprovisioning.OTPAuthURI; import com.lochbridge.oath.otp.keyprovisioning.OTPAuthURIBuilder; import com.lochbridge.oath.otp.keyprovisioning.OTPKey; import com.lochbridge.oath.otp.keyprovisioning.OTPKey.OTPType; import com.lochbridge.oath.otp.keyprovisioning.qrcode.QRCodeWriter.ErrorCorrectionLevel; public class TestQRCodeWriter { private static Path pathOfQRCodeImage = null; private static OTPAuthURI TOTP_AUTH_URI = null; @BeforeClass public static void setUp() throws IOException { pathOfQRCodeImage = Files.createTempFile("qrcode", "png", new FileAttribute[] {}); OTPKey key = new OTPKey(BaseEncoding.base32().encode("12345678901234567890".getBytes(StandardCharsets.US_ASCII)), OTPType.TOTP); String issuer = "Acme Corporation"; String accountName = "Alice Smith"; String label = String.format("%s:%s", issuer, accountName); TOTP_AUTH_URI = OTPAuthURIBuilder.fromKey(key).label(label).issuer(issuer).digits(6).timeStep(TimeUnit.SECONDS.toMillis(30)).build(); } @AfterClass public static void tearDown() { if (pathOfQRCodeImage != null) { File file = pathOfQRCodeImage.toFile(); if (file.exists()) { file.delete(); } } } private static String getQRCodeImageRawText(Path path) throws IOException, NotFoundException { Map<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>(); hints.put(DecodeHintType.CHARACTER_SET, StandardCharsets.UTF_8.name()); try(FileInputStream fis = new FileInputStream(path.toFile())) { BufferedImage bi = ImageIO.read(fis); BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(new BufferedImageLuminanceSource(bi))); Result result = new MultiFormatReader().decode(binaryBitmap, hints); return result.getText(); } } @Test(expected = NullPointerException.class) public void fromURIShouldFailWhenURIArgumentIsNull() { QRCodeWriter.fromURI(null); } @Test(expected = NullPointerException.class) public void writeToFileShouldFailWhenPathArgumentIsNull() throws IOException { QRCodeWriter.fromURI(TOTP_AUTH_URI).write((Path) null); } @Test(expected = NullPointerException.class) public void writeToOutputStreamShouldFailWhenStreamArgumentIsNull() throws IOException { QRCodeWriter.fromURI(TOTP_AUTH_URI).write((OutputStream) null); } @Test public void writeToFileShouldSucceedWhenQRCodeIsBasedOffTheURIString() throws IOException, NotFoundException { QRCodeWriter.fromURI(TOTP_AUTH_URI) .width(300) .height(300) .errorCorrectionLevel(ErrorCorrectionLevel.H) .margin(4) .imageFormatName("PNG") .write(pathOfQRCodeImage); assertEquals(TOTP_AUTH_URI.toUriString(), getQRCodeImageRawText(pathOfQRCodeImage)); } @Test public void writeToOutputStreamShouldSucceedWhenQRCodeIsBasedOffTheURIString() throws IOException, NotFoundException { QRCodeWriter.fromURI(TOTP_AUTH_URI) .width(300) .height(300) .errorCorrectionLevel(ErrorCorrectionLevel.H) .margin(4) .imageFormatName("PNG") .write(new FileOutputStream(pathOfQRCodeImage.toFile())); assertEquals(TOTP_AUTH_URI.toUriString(), getQRCodeImageRawText(pathOfQRCodeImage)); } }