diff --git a/.gitignore b/.gitignore
index 1bc94f3..d08c7af 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,4 @@
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
/.idea/
+/target
\ No newline at end of file
diff --git a/README.md b/README.md
index 44dea50..d4c303d 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,9 @@
# BinaryTattoo
+Transform text into it's binary representation (ASCII) in many ways with this lovely little cmd line tool!
-The goal of this project is to provide binary representation of the ASCII character code points. Basic usage is to print them in vertical or horizontal direction, for making a tattoo out of it.
+# Usage
+* '-i' (required) - input to be binarized (string; might some wise sentence, like 'I never don't give up')
+* '-s' (optional) - separator you want to use in between the binary words (I discourage to use '0' or '1', for obvious reasons). Defaults to ' ' (single space)
+* '-d' (optional) - the direction in which the binarized tattoo will be printed. Available options in 2D world are: 'HORIZONTAL' and 'VERTICAL'. Sorry non-euclideans...
+
+Have any suggestions? Well, I don't care, this is my baby and I will implement only the things I want (or even less, due to procrastination)
diff --git a/pom.xml b/pom.xml
index 3348a7f..bed6a7f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -17,10 +17,77 @@
8
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.2.0
+
+
+
+ Main
+
+
+
+
+
+
+ maven-assembly-plugin
+
+
+
+ Main
+
+
+
+ jar-with-dependencies
+
+
+
+
+ package
+
+ single
+
+
+
+
+
+ org.projectlombok
+ lombok
+ 1.18.16
+
+
+
+ org.slf4j
+ slf4j-simple
+ 1.6.4
+
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ 5.5.2
+ test
+
+
+
+ org.mockito
+ mockito-all
+ 1.10.19
+ test
+
+
+
+ commons-cli
+ commons-cli
+ 1.4
+
+
diff --git a/src/main/java/BinaryParser.java b/src/main/java/BinaryParser.java
new file mode 100644
index 0000000..f8bf35d
--- /dev/null
+++ b/src/main/java/BinaryParser.java
@@ -0,0 +1,43 @@
+import lombok.extern.slf4j.Slf4j;
+import model.BinaryLetter;
+import model.BinaryWord;
+
+@Slf4j
+public class BinaryParser {
+
+ public static BinaryWord parseBinaryWord(String input) {
+ log.info("Parsing input: {}", input);
+ long startTime = System.currentTimeMillis();
+
+ BinaryWord word = new BinaryWord();
+ for (char c : input.toCharArray()) {
+ word.appendLetter(parseBinaryLetter(c));
+ }
+
+ long duration = System.currentTimeMillis() - startTime;
+ log.info("Parsing complete, result: {} (took: {}ms)", word, duration);
+ return word;
+ }
+
+ private static BinaryLetter parseBinaryLetter(char input) {
+ int divider = 1;
+
+ // Find closest binary incrementation, i.e. 8, 16, 32 etc...
+ while (input > divider) {
+ divider *= 2;
+ }
+
+ BinaryLetter.Builder letterBuilder = new BinaryLetter.Builder();
+ while (divider > 0) {
+ if (input >= divider) {
+ letterBuilder.appendBit(true);
+ input -= divider;
+ } else {
+ letterBuilder.appendBit(false);
+ }
+ divider /= 2;
+ }
+
+ return letterBuilder.build();
+ }
+}
diff --git a/src/main/java/BinaryTattoo.java b/src/main/java/BinaryTattoo.java
new file mode 100644
index 0000000..0a0d1e5
--- /dev/null
+++ b/src/main/java/BinaryTattoo.java
@@ -0,0 +1,29 @@
+import lombok.extern.slf4j.Slf4j;
+import model.BinaryWord;
+import model.TattooData;
+import model.phrase.BinaryPhrase;
+import model.phrase.BinaryPhraseBuilder;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+@Slf4j
+public class BinaryTattoo {
+
+ private static final String DEFAULT_SEPARAOR = " ";
+
+ public static String toBinaryString(TattooData tattooData) {
+
+ final List words = Stream.of(tattooData.tattooString().split(DEFAULT_SEPARAOR))
+ .map(BinaryParser::parseBinaryWord).collect(Collectors.toList());
+
+ final BinaryPhrase phrase = new BinaryPhraseBuilder()
+ .words(words)
+ .separator(tattooData.separator())
+ .direction(tattooData.printDirection())
+ .build();
+
+ return phrase.toString();
+ }
+}
diff --git a/src/main/java/CmdLineTattooParser.java b/src/main/java/CmdLineTattooParser.java
new file mode 100644
index 0000000..ad72c2b
--- /dev/null
+++ b/src/main/java/CmdLineTattooParser.java
@@ -0,0 +1,88 @@
+import lombok.extern.slf4j.Slf4j;
+import model.TattooData;
+import model.phrase.PrintDirection;
+import org.apache.commons.cli.*;
+
+import java.util.Arrays;
+import java.util.stream.Collectors;
+
+@Slf4j
+public class CmdLineTattooParser {
+
+ public static final String INPUT_FLAG = "i";
+ public static final String INPUT_FLAG_DESCRIPTION = "input string to be binarized";
+
+ public static final String SEPARATOR_FLAG = "s";
+ public static final String SEPARATOR_FLAG_DESCRIPTION = "word separator (default: space, i.e. ' ')";
+ public static final String DEFAULT_SEPARATOR = " ";
+
+ public static final String DIRECTION_FLAG = "d";
+ public static final String DIRECTION_FLAG_DESCRIPTION = "print direction (default: vertical)";
+ public static final PrintDirection DEFAULT_DIRECTION = PrintDirection.VERTICAL;
+
+ public TattooData readArgs(String[] args) throws ParseException {
+ Options cmdOptions = buildOptions();
+ try {
+ CommandLine parsedArgs = new DefaultParser().parse(cmdOptions, args);
+
+ return parseTattooData(parsedArgs);
+ } catch (IllegalArgumentException ex) {
+ String generalMessage = String.format("Unable to parse input, cause: %s", ex.getMessage());
+ printHelp(generalMessage, cmdOptions);
+ throw new ParseException(generalMessage);
+ }
+ }
+
+ private Options buildOptions() {
+ Options cmdOptions = new Options();
+ cmdOptions.addOption(new Option(INPUT_FLAG, true, INPUT_FLAG_DESCRIPTION));
+ cmdOptions.addOption(new Option(SEPARATOR_FLAG, true, SEPARATOR_FLAG_DESCRIPTION));
+ cmdOptions.addOption(new Option(DIRECTION_FLAG, true, DIRECTION_FLAG_DESCRIPTION));
+ return cmdOptions;
+ }
+
+ private TattooData parseTattooData(CommandLine parsedArgs) {
+ String tattooString = parsedArgs.getOptionValue(INPUT_FLAG);
+ if (tattooString == null || tattooString.isEmpty()) {
+ throw new IllegalArgumentException("Input tattoo string cannot be empty!");
+ }
+ if (tattooString.length() > 100000) {
+ throw new IllegalArgumentException("Seriously? You don't have long enough body for this shit");
+ }
+
+ log.trace("Provided tattooString is correct: '{}'", tattooString);
+ TattooData tattooData = new TattooData(tattooString);
+
+ String separator = parsedArgs.getOptionValue(SEPARATOR_FLAG);
+ if (separator == null || separator.isEmpty()) {
+ log.warn("You've provided empty separator, defaulting to '{}'", DEFAULT_SEPARATOR);
+ tattooData.separator(DEFAULT_SEPARATOR);
+ } else {
+ if (separator.length() > 100) {
+ log.warn("Seriously? Such long separation should only be between you and this program..");
+ tattooData.separator(DEFAULT_SEPARATOR);
+ } else {
+ log.trace("Provided separator is correct: '{}'", separator);
+ tattooData.separator(separator);
+ }
+ }
+
+ try {
+ String directionString = parsedArgs.getOptionValue(DIRECTION_FLAG);
+ tattooData.printDirection(PrintDirection.valueOf(directionString));
+ log.trace("Provided print direction is correct: '{}'", directionString);
+ } catch (IllegalArgumentException ex) {
+ log.error("Invalid print direction specified, allowed values: {}, defaulting to: {}",
+ Arrays.stream(PrintDirection.values()).map(PrintDirection::toString).collect(Collectors.joining(",")),
+ DEFAULT_DIRECTION);
+ tattooData.printDirection(DEFAULT_DIRECTION);
+ }
+
+ return tattooData;
+ }
+
+ private void printHelp(String generalMessage, Options options) {
+ log.error(generalMessage);
+ new HelpFormatter().printHelp("[packaged_jar]", options);
+ }
+}
diff --git a/src/main/java/Main.java b/src/main/java/Main.java
new file mode 100644
index 0000000..fb0534f
--- /dev/null
+++ b/src/main/java/Main.java
@@ -0,0 +1,14 @@
+import model.TattooData;
+import org.apache.commons.cli.ParseException;
+
+public class Main {
+
+ public static void main(String[] args) {
+ try {
+ TattooData tattooData = new CmdLineTattooParser().readArgs(args);
+ System.out.println(BinaryTattoo.toBinaryString(tattooData));
+ } catch (ParseException ex) {
+ // CmdLineTattooParser print help message, we just want to 'Enjoy the silence' here
+ }
+ }
+}
diff --git a/src/main/java/model/BinaryLetter.java b/src/main/java/model/BinaryLetter.java
new file mode 100644
index 0000000..e56c6f6
--- /dev/null
+++ b/src/main/java/model/BinaryLetter.java
@@ -0,0 +1,69 @@
+package model;
+
+import java.util.ArrayDeque;
+import java.util.Queue;
+
+public class BinaryLetter {
+
+ private final Queue bits;
+
+ private BinaryLetter(Builder b) {
+ this.bits = b.bits;
+ }
+
+ public boolean hasNextBit() {
+ return !bits.isEmpty();
+ }
+
+ public boolean pollNextBit() {
+ Boolean bit = bits.poll();
+ if (bit == null) {
+ throw new IllegalArgumentException("No bits left!");
+ }
+ return bit;
+ }
+
+ /**
+ * Return the number of bits, that consists to the letter
+ *
+ * @return number of bits
+ */
+ public int length() {
+ return bits.size();
+ }
+
+ @Override
+ public String toString() {
+ return bits.stream()
+ .map(bit -> bit ? "1" : "0")
+ .reduce(String::concat)
+ .orElse("!");
+ }
+
+ public static class Builder {
+ private int bitRange = 8;
+ private final Queue bits = new ArrayDeque<>();
+
+ public Builder bitRange(int bitRange) {
+ this.bitRange = bitRange;
+ return this;
+ }
+
+ /**
+ * Sets the next bit, from left to right.
+ *
+ * @param bit true (1), or false (0)
+ */
+ public Builder appendBit(boolean bit) {
+ bits.add(bit);
+ return this;
+ }
+
+ public BinaryLetter build() throws IllegalArgumentException {
+ if (bitRange < 1 || bits.size() != bitRange) {
+ throw new IllegalArgumentException("Invalid bit range!");
+ }
+ return new BinaryLetter(this);
+ }
+ }
+}
diff --git a/src/main/java/model/BinaryWord.java b/src/main/java/model/BinaryWord.java
new file mode 100644
index 0000000..edbd4f9
--- /dev/null
+++ b/src/main/java/model/BinaryWord.java
@@ -0,0 +1,42 @@
+package model;
+
+import java.util.ArrayDeque;
+import java.util.Queue;
+
+public class BinaryWord {
+
+ private final Queue letters = new ArrayDeque<>();
+
+ public void appendLetter(BinaryLetter letter) {
+ letters.add(letter);
+ }
+
+ public boolean hasNextLetter() {
+ return !letters.isEmpty();
+ }
+
+ public BinaryLetter pollNextLetter() {
+ BinaryLetter letter = letters.poll();
+ if (letter == null) {
+ throw new IllegalArgumentException("No letters left!");
+ }
+ return letter;
+ }
+
+ /**
+ * Return the number of bits, that consists to the word
+ *
+ * @return number of bits
+ */
+ public int length() {
+ return letters.stream().map(BinaryLetter::length).reduce(Integer::sum).orElse(0);
+ }
+
+ @Override
+ public String toString() {
+ return letters.stream()
+ .map(BinaryLetter::toString)
+ .reduce((letter1, letter2) -> letter1 + " " + letter2)
+ .orElse("EMPTY");
+ }
+}
diff --git a/src/main/java/model/TattooData.java b/src/main/java/model/TattooData.java
new file mode 100644
index 0000000..1b981c2
--- /dev/null
+++ b/src/main/java/model/TattooData.java
@@ -0,0 +1,18 @@
+package model;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import model.phrase.PrintDirection;
+
+@Setter
+@Getter
+@Accessors(fluent = true)
+@RequiredArgsConstructor
+public class TattooData {
+
+ private final String tattooString;
+ private String separator;
+ private PrintDirection printDirection;
+}
diff --git a/src/main/java/model/phrase/BinaryPhrase.java b/src/main/java/model/phrase/BinaryPhrase.java
new file mode 100644
index 0000000..bcf5db5
--- /dev/null
+++ b/src/main/java/model/phrase/BinaryPhrase.java
@@ -0,0 +1,20 @@
+package model.phrase;
+
+import model.BinaryWord;
+
+public abstract class BinaryPhrase {
+ protected static final int BIT_RANGE = 8;
+
+ protected final boolean[][] bitMatrix;
+ protected int heightCursor = 0;
+ protected int widthCursor = 0;
+ protected final String separator;
+
+ protected BinaryPhrase(int maxWidth, int maxHeight, String separator) {
+ this.bitMatrix = new boolean[maxHeight][maxWidth];
+ this.separator = separator;
+ }
+
+ protected abstract void appendBitWord(BinaryWord word);
+}
+
diff --git a/src/main/java/model/phrase/BinaryPhraseBuilder.java b/src/main/java/model/phrase/BinaryPhraseBuilder.java
new file mode 100644
index 0000000..44fdd78
--- /dev/null
+++ b/src/main/java/model/phrase/BinaryPhraseBuilder.java
@@ -0,0 +1,39 @@
+package model.phrase;
+
+import model.BinaryWord;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class BinaryPhraseBuilder {
+
+ private Collection words = new ArrayList<>();
+ private PrintDirection direction = PrintDirection.HORIZONTAL;
+ private String separator;
+
+ public BinaryPhraseBuilder direction(PrintDirection d) {
+ this.direction = d;
+ return this;
+ }
+
+ public BinaryPhraseBuilder words(Collection words) {
+ this.words = words;
+ return this;
+ }
+
+ public BinaryPhraseBuilder separator(String separator) {
+ this.separator = separator;
+ return this;
+ }
+
+ public BinaryPhrase build() {
+ int longestWordLength = words.stream().map(BinaryWord::length).reduce(Integer::max).orElse(0);
+ int wordCount = words.size();
+
+ if (PrintDirection.HORIZONTAL.equals(direction)) {
+ return new HorizontalBinaryPhrase(longestWordLength, wordCount, separator, words);
+ } else {
+ return new VerticalBinaryPhrase(wordCount, longestWordLength, separator, words);
+ }
+ }
+}
diff --git a/src/main/java/model/phrase/HorizontalBinaryPhrase.java b/src/main/java/model/phrase/HorizontalBinaryPhrase.java
new file mode 100644
index 0000000..6a50b08
--- /dev/null
+++ b/src/main/java/model/phrase/HorizontalBinaryPhrase.java
@@ -0,0 +1,45 @@
+package model.phrase;
+
+import model.BinaryLetter;
+import model.BinaryWord;
+
+import java.util.Collection;
+
+public class HorizontalBinaryPhrase extends BinaryPhrase {
+
+ public HorizontalBinaryPhrase(int maxWidth, int maxHeight, String separator, Collection words) {
+ super(maxWidth, maxHeight, separator);
+ words.forEach(this::appendBitWord);
+ }
+
+ @Override
+ protected void appendBitWord(BinaryWord word) {
+
+ while (word.hasNextLetter()) {
+ BinaryLetter letter = word.pollNextLetter();
+ while (letter.hasNextBit()) {
+ boolean bit = letter.pollNextBit();
+ bitMatrix[heightCursor][widthCursor] = bit;
+ widthCursor++;
+ }
+ }
+ widthCursor = 0;
+ heightCursor++;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ for (boolean[] row : bitMatrix) {
+ for (int j = 0; j < row.length; j++) {
+ sb.append(row[j] ? '1' : '0');
+ if ((j+1) % BIT_RANGE == 0) {
+ sb.append(separator);
+ }
+ }
+ sb.append("\n");
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/src/main/java/model/phrase/PrintDirection.java b/src/main/java/model/phrase/PrintDirection.java
new file mode 100644
index 0000000..3188f22
--- /dev/null
+++ b/src/main/java/model/phrase/PrintDirection.java
@@ -0,0 +1,5 @@
+package model.phrase;
+
+public enum PrintDirection {
+ HORIZONTAL, VERTICAL
+}
diff --git a/src/main/java/model/phrase/VerticalBinaryPhrase.java b/src/main/java/model/phrase/VerticalBinaryPhrase.java
new file mode 100644
index 0000000..f1c4606
--- /dev/null
+++ b/src/main/java/model/phrase/VerticalBinaryPhrase.java
@@ -0,0 +1,46 @@
+package model.phrase;
+
+import model.BinaryLetter;
+import model.BinaryWord;
+
+import java.util.Collection;
+
+public class VerticalBinaryPhrase extends BinaryPhrase {
+
+ public VerticalBinaryPhrase(int maxWidth, int maxHeight, String separator, Collection words) {
+ super(maxWidth, maxHeight, separator);
+ words.forEach(this::appendBitWord);
+ }
+
+ @Override
+ protected void appendBitWord(BinaryWord word) {
+
+ while (word.hasNextLetter()) {
+ BinaryLetter letter = word.pollNextLetter();
+ while (letter.hasNextBit()) {
+ boolean bit = letter.pollNextBit();
+ bitMatrix[heightCursor][widthCursor] = bit;
+ heightCursor++;
+ }
+ }
+ heightCursor = 0;
+ widthCursor++;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < bitMatrix.length; i++) {
+ boolean[] row = bitMatrix[i];
+ for (boolean b : row) {
+ sb.append(b ? '1' : '0').append(separator);
+ }
+ if ((i+1) % BIT_RANGE == 0) {
+ sb.append("\n");
+ }
+ sb.append("\n");
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/src/test/java/BinaryParserTest.java b/src/test/java/BinaryParserTest.java
new file mode 100644
index 0000000..835b80e
--- /dev/null
+++ b/src/test/java/BinaryParserTest.java
@@ -0,0 +1,33 @@
+import model.BinaryWord;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class BinaryParserTest {
+
+ @Test
+ public void parseWordTest() {
+ // given
+ final int defaultBitRange = 8;
+ String rawWord = "miscellaneous";
+
+ // when
+ BinaryWord parsedWord = BinaryParser.parseBinaryWord(rawWord);
+
+ // then
+ assertEquals(rawWord.length(), parsedWord.length()/defaultBitRange);
+ }
+
+ @Test
+ public void parseEmptyWordTest() {
+ // given
+ final int defaultBitRange = 8;
+ String rawWord = "";
+
+ // when
+ BinaryWord parsedWord = BinaryParser.parseBinaryWord(rawWord);
+
+ // then
+ assertEquals(0, parsedWord.length()/defaultBitRange);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/model/BinaryLetterTest.java b/src/test/java/model/BinaryLetterTest.java
new file mode 100644
index 0000000..cefe1ed
--- /dev/null
+++ b/src/test/java/model/BinaryLetterTest.java
@@ -0,0 +1,96 @@
+package model;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class BinaryLetterTest {
+
+ @Test
+ public void appendOnlyTest() {
+
+ // given
+ BinaryLetter.Builder letterBuilder = new BinaryLetter.Builder().bitRange(1);
+ letterBuilder.appendBit(true);
+
+ // when
+ BinaryLetter letter = letterBuilder.build();
+
+ // then
+ assertEquals(1, letter.length());
+ assertTrue(letter.hasNextBit());
+ }
+
+ @Test
+ public void appendAndPollTest() {
+
+ // given
+ boolean bit = true;
+ BinaryLetter.Builder letterBuilder = new BinaryLetter.Builder().bitRange(1);
+ letterBuilder.appendBit(true);
+ BinaryLetter letter = letterBuilder.build();
+
+ // when
+ boolean polledBit = letter.pollNextBit();
+
+ // then
+ assertEquals(bit, polledBit);
+ assertEquals(0, letter.length());
+ assertFalse(letter.hasNextBit());
+ }
+
+ @Test
+ public void lengthTest() {
+
+ // given
+ int bitsToAppend = 5;
+ int bitsToPoll = 3;
+ BinaryLetter.Builder letterBuilder = new BinaryLetter.Builder().bitRange(bitsToAppend);
+
+ // when
+ for (int i = 0; i < bitsToAppend; i++) {
+ letterBuilder.appendBit(true);
+ }
+
+ BinaryLetter letter = letterBuilder.build();
+ for (int i = 0; i < bitsToPoll; i++) {
+ letter.pollNextBit();
+ }
+
+ // then
+ assertEquals(2, letter.length());
+ }
+
+ @Test
+ public void buildEmptyLetterTest() {
+
+ // given
+ BinaryLetter.Builder letterBuilder = new BinaryLetter.Builder();
+
+ // when / then
+ assertThrows(IllegalArgumentException.class, letterBuilder::build);
+ }
+
+ @Test
+ public void negativeBitRangeTest() {
+
+ // given
+ BinaryLetter.Builder letterBuilder = new BinaryLetter.Builder().bitRange(-1);
+
+ // when / then
+ assertThrows(IllegalArgumentException.class, letterBuilder::build);
+ }
+
+ @Test
+ public void incompleteLetterTest() {
+
+ // given
+ BinaryLetter.Builder letterBuilder = new BinaryLetter.Builder()
+ .bitRange((byte)8)
+ .appendBit(true)
+ .appendBit(false);
+
+ // when / then
+ assertThrows(IllegalArgumentException.class, letterBuilder::build);
+ }
+}
diff --git a/src/test/java/model/BinaryWordTest.java b/src/test/java/model/BinaryWordTest.java
new file mode 100644
index 0000000..668b1ae
--- /dev/null
+++ b/src/test/java/model/BinaryWordTest.java
@@ -0,0 +1,87 @@
+package model;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+class BinaryWordTest {
+
+ @Test
+ public void appendOnlyTest() {
+
+ int bitsCountInLetter = 8;
+
+ // given
+ BinaryLetter letterMock = mock(BinaryLetter.class);
+ when(letterMock.length()).thenReturn(bitsCountInLetter);
+
+ // when
+ BinaryWord word = new BinaryWord();
+ word.appendLetter(letterMock);
+
+ // then
+ assertEquals(bitsCountInLetter, word.length());
+ assertTrue(word.hasNextLetter());
+ }
+
+ @Test
+ public void appendAndPollTest() {
+
+ // given
+ int bitsCountInLetter = 8;
+
+ BinaryLetter letterMock = mock(BinaryLetter.class);
+ when(letterMock.length()).thenReturn(bitsCountInLetter);
+
+ BinaryWord word = new BinaryWord();
+ word.appendLetter(letterMock);
+
+ // when
+ BinaryLetter polledLetter = word.pollNextLetter();
+
+ // then
+ assertEquals(letterMock, polledLetter);
+ assertEquals(0, word.length());
+ assertFalse(word.hasNextLetter());
+ }
+
+ @Test
+ public void lengthTest() {
+
+ // given
+ int bitsCountInLetter = 8;
+ int lettersToAppend = 5;
+ int lettersToPoll = 3;
+
+ BinaryLetter letterMock = mock(BinaryLetter.class);
+ when(letterMock.length()).thenReturn(bitsCountInLetter);
+
+ BinaryWord word = new BinaryWord();
+
+ // when
+ for (int i = 0; i < lettersToAppend; i++) {
+ word.appendLetter(letterMock);
+ }
+
+ for (int i = 0; i < lettersToPoll; i++) {
+ word.pollNextLetter();
+ }
+
+ // then
+ assertEquals((lettersToAppend-lettersToPoll)*bitsCountInLetter, word.length());
+ }
+
+ @Test
+ public void pollBitEmptyLetterTest() {
+
+ // given
+ BinaryWord word = new BinaryWord();
+
+ // when / then
+ assertEquals(0, word.length());
+ assertFalse(word.hasNextLetter());
+ assertThrows(IllegalArgumentException.class, word::pollNextLetter);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/model/phrase/BinaryPhraseBuilderTest.java b/src/test/java/model/phrase/BinaryPhraseBuilderTest.java
new file mode 100644
index 0000000..e258793
--- /dev/null
+++ b/src/test/java/model/phrase/BinaryPhraseBuilderTest.java
@@ -0,0 +1,44 @@
+package model.phrase;
+
+import model.BinaryWord;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class BinaryPhraseBuilderTest {
+
+ @Test
+ public void verticalTest() {
+
+ // given
+ Collection emptyWordCollection = new ArrayList<>();
+
+ // when
+ final BinaryPhrase phrase = new BinaryPhraseBuilder()
+ .words(emptyWordCollection)
+ .direction(PrintDirection.VERTICAL)
+ .build();
+
+ // then
+ assertEquals(VerticalBinaryPhrase.class, phrase.getClass());
+ }
+
+ @Test
+ public void horizontalTest() {
+
+ // given
+ Collection emptyWordCollection = new ArrayList<>();
+
+ // when
+ final BinaryPhrase phrase = new BinaryPhraseBuilder()
+ .words(emptyWordCollection)
+ .direction(PrintDirection.HORIZONTAL)
+ .build();
+
+ // then
+ assertEquals(HorizontalBinaryPhrase.class, phrase.getClass());
+ }
+}
diff --git a/src/test/java/model/phrase/BinaryPhraseTest.java b/src/test/java/model/phrase/BinaryPhraseTest.java
new file mode 100644
index 0000000..53c1b66
--- /dev/null
+++ b/src/test/java/model/phrase/BinaryPhraseTest.java
@@ -0,0 +1,112 @@
+package model.phrase;
+
+import model.*;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class BinaryPhraseTest {
+
+ private static final String SEPARATOR = " ";
+
+ @Test
+ public void emptyTest() {
+ // given
+ Collection words = new ArrayList<>();
+
+ // when
+ final BinaryPhrase phrase = new BinaryPhraseBuilder()
+ .words(words)
+ .direction(PrintDirection.VERTICAL)
+ .build();
+
+ // then
+ String actual = phrase.toString();
+ assertEquals("", actual);
+ }
+
+// @Test
+ public void verticalTest() {
+
+ String expected = "01000110" + SEPARATOR + "01001111" + SEPARATOR + "01010010" + SEPARATOR + "01010100" + SEPARATOR + "01001001" + SEPARATOR + "01010011" + SEPARATOR + "00000000" + SEPARATOR + "\n" +
+ "01000110" + SEPARATOR + "01001111" + SEPARATOR + "01010010" + SEPARATOR + "01010100" + SEPARATOR + "01010101" + SEPARATOR + "01001110" + SEPARATOR + "01000001 \n" +
+ "01000001" + SEPARATOR + "01000100" + SEPARATOR + "01001010" + SEPARATOR + "01010101" + SEPARATOR + "01010110" + SEPARATOR + "01000001" + SEPARATOR + "01010100 ";
+
+ // given
+ Collection words = new ArrayList<>();
+
+ // when
+ final BinaryPhrase phrase = new BinaryPhraseBuilder()
+ .words(words)
+ .direction(PrintDirection.VERTICAL)
+ .build();
+
+ // then
+ String actual = phrase.toString();
+ assertEquals(expected, actual);
+ }
+
+// @Test
+ public void horizontalTest() {
+
+ String expected = "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" +
+ "1" + SEPARATOR + "1" + SEPARATOR + "1" + SEPARATOR + "\n" +
+ "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" +
+ "1" + SEPARATOR + "1" + SEPARATOR + "0" + SEPARATOR + "\n" +
+ "0" + SEPARATOR + "0" + SEPARATOR + "1" + SEPARATOR + "\n" +
+ "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" +
+ "1" + SEPARATOR + "1" + SEPARATOR + "1" + SEPARATOR + "\n" +
+ "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" +
+ "\n" +
+ "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" +
+ "1" + SEPARATOR + "1" + SEPARATOR + "1" + SEPARATOR + "\n" +
+ "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" +
+ "1" + SEPARATOR + "1" + SEPARATOR + "1" + SEPARATOR + "\n" +
+ "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" +
+ "1" + SEPARATOR + "1" + SEPARATOR + "1" + SEPARATOR + "\n" +
+ "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" +
+ "0" + SEPARATOR + "0" + SEPARATOR + "1" + SEPARATOR + "\n" +
+ "\n" +
+ "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" +
+ "1" + SEPARATOR + "1" + SEPARATOR + "1" + SEPARATOR + "\n" +
+ "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" +
+ "0" + SEPARATOR + "1" + SEPARATOR + "1" + SEPARATOR + "\n" +
+ "1" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" +
+ "0" + SEPARATOR + "1" + SEPARATOR + "1" + SEPARATOR + "\n" +
+ "0" + SEPARATOR + "0" + SEPARATOR + "1" + SEPARATOR + "\n" +
+ "1" + SEPARATOR + "1" + SEPARATOR + "0" + SEPARATOR + "\n" +
+ "\n" +
+ "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" +
+ "1" + SEPARATOR + "1" + SEPARATOR + "1" + SEPARATOR + "\n" +
+ "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" +
+ "1" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" +
+ "0" + SEPARATOR + "1" + SEPARATOR + "0" + SEPARATOR + "\n" +
+ "0" + SEPARATOR + "1" + SEPARATOR + "0" + SEPARATOR + "\n" +
+ "1" + SEPARATOR + "1" + SEPARATOR + "0" + SEPARATOR + "\n" +
+ "1" + SEPARATOR + "0" + SEPARATOR + "1" + SEPARATOR + "\n" +
+ "\n" +
+ "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" +
+ "0" + SEPARATOR + "1" + SEPARATOR + "1" + SEPARATOR + "\n" +
+ "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" +
+ "0" + SEPARATOR + "0" + SEPARATOR + "1" + SEPARATOR + "\n" +
+ "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" +
+ "0" + SEPARATOR + "0" + SEPARATOR + "1" + SEPARATOR + "\n" +
+ "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" +
+ "0" + SEPARATOR + "1" + SEPARATOR + "0" + SEPARATOR + "";
+
+ // given
+ Collection words = new ArrayList<>();
+
+ // when
+ final BinaryPhrase phrase = new BinaryPhraseBuilder()
+ .words(words)
+ .direction(PrintDirection.HORIZONTAL)
+ .build();
+
+ // then
+ assertEquals(expected, phrase.toString());
+ }
+}