Roman Numbers Converter

package de.sambalmueslie.number_convert;

import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class RomanNumberConverter implements NumberConverter {

	private class MappingEntry {

		public MappingEntry(final int number, final char symbol) {
			this(number, symbol, false);
		}

		public MappingEntry(final int number, final char symbol, final boolean subtractable) {
			this.number = number;
			this.symbol = symbol;
			this.subtractable = subtractable;
		}

		private final int number;
		private final boolean subtractable;
		private final char symbol;
	}

	public RomanNumberConverter() {
		mappings.add(new MappingEntry(1, 'I', true));
		mappings.add(new MappingEntry(5, 'V'));
		mappings.add(new MappingEntry(10, 'X', true));
		mappings.add(new MappingEntry(50, 'L'));
		mappings.add(new MappingEntry(100, 'C', true));
		mappings.add(new MappingEntry(500, 'D'));
		mappings.add(new MappingEntry(1000, 'M'));
	}

	@Override
	public String convert(final int value) {
		final StringBuffer result = new StringBuffer();

		int remaining = value;

		final int start = mappings.size() - 1;
		for (int index = start; index >= 0; index--) {
			final MappingEntry current = mappings.get(index);
			final MappingEntry next = index > 0 ? mappings.get(index - 1) : null;
			final MappingEntry doubleNext = index > 1 ? mappings.get(index - 2) : null;

			final int number = current.number;
			final boolean matches = remaining >= number;
			if (matches) {
				final int amount = remaining / number;
				result.append(concat(current.symbol, amount));
				remaining -= number * amount;
			} else if (next != null && next.subtractable && remaining >= number - next.number) {
				result.append(next.symbol + "" + current.symbol);
				remaining -= number - next.number;
			} else if (doubleNext != null && doubleNext.subtractable && remaining >= number - doubleNext.number) {
				result.append(doubleNext.symbol + "" + current.symbol);
				remaining -= number - doubleNext.number;
			}

		}
		return result.toString();
	}

	@Override
	public int convert(final String value) {
		final List<Integer> numbers = value.chars().map(t -> find(t).number).boxed().collect(Collectors.toList());
		for (int i = 0; i < numbers.size() - 1; i++) {
			if (numbers.get(i) < numbers.get(i + 1)) {
				numbers.set(i, numbers.get(i) * -1);
			}
		}
		return numbers.stream().mapToInt(t -> t).sum();
	}

	private String concat(final char c, final int amount) {
		final StringBuffer sb = new StringBuffer();
		Stream.generate(() -> c).limit(amount).forEach(t -> sb.append(t));
		return sb.toString();
	}

	private MappingEntry find(final Integer c) {
		final Optional<MappingEntry> result = mappings.stream().filter(n -> n.symbol == c).findFirst();
		return result.isPresent() ? result.get() : null;
	}

	private final List<MappingEntry> mappings = new LinkedList<>();
}

My personal vision of testing software

There are several different practices and scopes of software testing but I will focus on testing during development. If you work in a very small project or alone on a piece of software, it could be easier to test your software by click around on the ui and check if it works how it should. But if things go a little bit bigger this style of testing produces some huge problems:

  1. Deploying your software and click around on the gui takes a lot of time.
  2. There are no regressions, if your feature works and you work on the next one, the first would be broken and if you forget to try it out again your software fail.
  3. There is no possibility to let the tests executed by some continuous integration server like Jenkins for example.

So if your code reaches a couple of lines, high quality work without testing would be nearly impossible or takes a lot of time until it works and if you change it a little bit it could end up in a mess very fast. But when you start this looks very simple and straight forward. It’s a little bit like a jenga tower. You build it up and checked everything. Let’s imagine it works and your customer is satisfied, but what if he wants some minor changes. Every change is like pull out a piece of the tower. If you change it enough times, he will fall down. So therefore you need something reliable which guarantees you, that your changes only produces the result your customer wants and not changing anything else. But how could you deal with it, if you have a lot of pressure and your schedule is very tight?

My personal vision of testing software weiterlesen