
## Verificação e Validação de Software
### Professor:
José Campos
### Alunos:
João Lopes nº55812
Filipe Martins nº55814
# Assignment #2
Este assignment consiste na realização de testes unitarios, sendo estes testes do tipo *Black-Box Testing* e através do metodo Category-Partition.Para tal tivemos de identificar 5 funções do projeto Jpass para testar, tendo estas de pertencer ao pacote assignado **jpass.util**.
O Category-Partition proporciona-nos uma forma sistemática de desenvolver
testes derivados, com base nas características dos parametros das funções
parâmetros. Através disto conseguimos reduzir o número de testes a um
número prático.
Para a realização dos testes unitários utilizamos a ferramente JUnit, que é uma das ferramentas mais utilizadas na criação de testes unitários para Java.
Neste assignment consta uma breve explicação da função a ser testada, como foi utilizada a category-partition e quais os testes a realizar para a mesma, e por fim uma explicação dos testes desenvolvidos e também os resultados obtidos.
## Função - 1
Esta função tem como propósito remover todos os caracteres que não são imprimíveis, para tal é utilizado um *loop* pelos caracteres da `String` fornecida como parâmetro e é verificado se cada caracter é ou não imprimível, utilizando o seu valor hexadecimal, caso o caracter não seja imprimível é substituído por o caracter `'?'`.
```
public static String stripNonValidXMLCharacters(final String in) {
if (in == null || in.isEmpty()) {
return in;
}
StringBuilder out = new StringBuilder();
char current;
for (int i = 0; i < in.length(); i++) {
current = in.charAt(i);
if ((current == 0x9) || (current == 0xA) || (current == 0xD)
|| ((current >= 0x20) && (current <= 0xD7FF))
|| ((current >= 0xE000) && (current <= 0xFFFD))) {
out.append(current);
} else {
out.append('?');
}
}
return out.toString();
}
```
**Category-Partition**
Em termos dos parâmetros existentes nesta função, só temos um, que é uma `String`, este parâmetro não pode ser *null* nem vazio, de resto pode ter qualquer valor valido para uma string, seja ele imprimível ou não.
Desta forma obtemos os testes possíveis a desenvolver:
* `String` com o valor *null*.
* `String` com o valor vazio.
* `String` com caracteres não imprimíveis.
* `String` sem caracteres não imprimíveis.
**Testes unitários**
No primeiro teste o objetivo era verificar se a função conseguia ou não lidar com o parâmetro *null*, após a sua realização concluímos que a função lida bem com este caso, sendo retornado o valor fornecido, neste caso *null*.
Seguiu-se o teste onde pretendemos verificar se a função lidava bem com um parâmetro vazio, tal como no teste prévio. Também concluímos que a função lida bem com strings vazias, retornando a mesma.
O terceiro teste teve como objetivo verificar se a função realmente substitui os caracteres não imprimíveis, para tal utilizamos o caracter � e mais quatro caracteres que eram imprimíveis.
No final verificamos que a string retornada tinha o caracter substituído, tendo, portanto, funcionado como previsto.
Por fim foi testada uma string sem caracteres não imprimíveis, onde era previsto não ser feita qualquer alteração a string fornecida.
Após execução do teste conseguimos comprovar o que tinha sido previsto, ou seja, nenhum dos caracteres presentes na string foi alterado.
## Função - 2
A função `formatIsoDateTime` tem como objetivo receber uma data em formato `String` e retornar a mesma transformada no formato pretendido. Para tal recebe 2 argumentos, uma data em formato `String` e `DateTimeFormatter` com o formato que deve ser aplicado à data.
Em primeiro lugar a função tenta transformar a data passada como argumento para o formato desejado, caso não seja possível, a função tenta criar uma variável `Date` com a string passada como argumento, caso também não seja possível a função devolve uma a primeira data conhecido ’01.01.1970 ’no formata desejado.
```
public static String formatIsoDateTime(String dateString, DateTimeFormatter formatter) {
LocalDateTime dateTime;
try {
dateTime = LocalDateTime.parse(dateString, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
} catch (DateTimeParseException | NullPointerException e) {
try {
// fallback to epoch timestamp
Date date = new Date(Long.parseLong(dateString));
dateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
} catch (NumberFormatException | DateTimeParseException | NullPointerException ex) {
dateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(0), ZoneId.systemDefault());
}
}
return formatter.format(dateTime.truncatedTo(ChronoUnit.SECONDS));
}
```
**Category-Partition**
Em relação aos parâmetros existentes nesta função, temos dois, uma data do tipo `String`, e um `DateTimeFormatter`, que corresponde a formatação desejada para a data fornecida. Em termos de características/restrições, ambos os parâmetros só não podiam ser nulos.
De forma a testar todas as formas possíveis foram criadas as seguintes categorias. Um `DateTimeFormatter`: *null*, vazio, correto ou incorreto sendo que para cada uma destas hipóteses será utilizada uma string com uma data correta, incorreta, vazia ou *null*.
Assim obtemos os possíveis testes a desenvolver:
* `DateTimeFormatter` vazio.
* `DateTimeFormatter` `null` com uma data correcta.
* `DateTimeFormatter` `null` com uma data incorreta.
* `DateTimeFormatter` `null` com uma data vazia.
* `DateTimeFormatter` `null` com uma data `null`.
* `DateTimeFormatter` incorreto com uma data correcta.
* `DateTimeFormatter` incorreto com uma data incorreta.
* `DateTimeFormatter` incorreto com uma data vazia.
* `DateTimeFormatter` incorreto com uma data `null`.
* `DateTimeFormatter` correto com uma data correcta.
* `DateTimeFormatter` correto com uma data incorreta.
* `DateTimeFormatter` correto com uma data vazia.
* `DateTimeFormatter` correto com uma data `null`.
**Testes Unitários**
Para começar foi feito um teste com o `DateTimeFormatter` a vazio, a função devolve uma string vazia, apesar de não serem levantadas exceções, esta situação sugere que a função deve ser revista pois esta não aparenta ser o comportamento desejado.
Para a segunda bateria de testes no qual o `DateTimeFormatter` esta fixo com o valor `null` sendo o único ponto de variação na data. Todos os testes deram conforme esperado, o que sugere que os métodos foram bem implementados.
Para a terceira bateria de testes o parâmetro `DateTimeFormatter` foi testado com o valor da incorreto e com a data a `null` Todos os testes deram positivo.
Por fim bastou testar o `DateTimeFormatter` correto fixo com variação na data. Todos os testes deram positivo.
## Função - 3
O Propósito da função `createFormatter` é de através de um padrão de datas do tipo `String` recebido como parâmetro, ex. (01-01-2010), caso este seja valido, transformá-lo num objeto do tipo `DateTimeFormatter` de modo a formatar datas do tipo `DateTime`.
A função recebe o padrão desejado como string e tenta criar um objeto do tipo `DateTimeFormatter` utilizando o método `DateTimeFormatter.ofPattern(String pattern)`, caso o padrão seja valido o objeto será criado e retornado pela função, caso seja invalido o método tentará apanhar uma exceção do tipo `IllegalArgumentException`, que indica que o padrão não é um padrão valido para formatar datas, ou uma exceção do tipo `NullPointerException` caso o padrão esteja a *null*. Nestes casos o método retorna um `DateTimeFormatter` pré-definido utilizando o padrão `ISO_DATE`.
```
public static DateTimeFormatter createFormatter(String format){
DateTimeFormatter formatter;
try {
formatter = DateTimeFormatter.ofPattern(format);
} catch (IllegalArgumentException | NullPointerException e) {
LOG.log(Level.WARNING, String.format("Could not parse date format [%s] due to [%s]", format, e.getMessage()));
formatter = DateTimeFormatter.ISO_DATE;
}
return formatter;
}
```
**Category-Partition**
De modo a testarmos o método especificado dividimos os testes em categorias, e desta forma cobrindo todos os possíveis resultados da função. Para tal inicialmente analisamos o tipo de parâmetro necessário e qual o seria o resultado esperado, assim sendo começamos por separar em 2 partes, parâmetro com valor e sem valor.
Começando pela primeira parte, verificamos que caso o padrão fornecido fosse valido deveria ser retornado o `DateTimeFormatter` específico, mas caso o mesmo seja invalido deveria ser retornado um `DateTimeFormatter` definido internamente. Assim ficamos com as duas primeiras categorias:
* Parametro `format` com um valor valido. Exemplo: `"21.12.2021"`
* Parametro `format` com um valor invalido. Exemplo: `"21.12.202"`
Passando para a segunda parte, verificamos que tanto podemos passar um padrão a `null` como um padrão vazio. Em ambos os casos deve ser retornado o `DateTimeFormatter` definido internamente. Desta forma obtemos as restantes categorias:
* Parametro `format` com o valor null. Exemplo: `null`
* Parametro `format` com o valor vazio. Exemplo: `""`
**Testes Unitários**
Tendo obtido quais os testes necessários a realizar, foram então criados e analisados, de modo a verificar se a função a ser avaliada se comportava como planeado.
Começando pelo teste para quando o padrão tem o valor *null*, o mesmo teve como objetivo verificar se a função conseguia lidar com o valor *null*.
Neste teste o valor esperado seria um `DateTimeFormatter` pré-definido internamente, algo que se sucedeu.
Desta forma concluímos que esta função consegue lidar bem com o valor *null*, e não emite exceções relacionadas com o mesmo.
Passando ao teste referente ao padrão ter um valor vazio, tal como no teste anterior, a função deveria retornar o `DateTimeFormatter` pré-definido internamente. Neste teste conseguimos perceber que o mesmo não ocorre, o que é retornado é um `DateTimeFormatter` vazio, ou seja, a função não verifica se o input é uma string vazia e deixa que esta seja utilizada para criar o objeto do tipo `DateTimeFormatter`.
Este problema pode levar a diversos erros, visto que esta função é utilizada para criar o formatador de datas, e desta forma várias datas irão ser apagadas com este formatador.
De seguida temos o teste para quando o padrão tem um valor invalido, neste caso, como o padrão fornecido não existe, e não é possível a criação do objeto `DateTimeFormatter`, deveria ser retornado o `DateTimeFormatter` pré-definido. Neste teste concluímos que o mesmo se sucede, ou seja, não é criado um formatador invalido, nem nos é emitida uma exceção, tal como seria esperado o `DateTimeFormatter` pré-definido é retornado.
Por fim temos o teste referente ao padrão ter um valor valido, este é o único caso onde deveria ser retornado o `DateTimeFormatter` com o padrão fornecido.
Após analise do teste verificamos que este é realmente o seu comportamento, retornando o `DateTimeFormatter` correto.
## Função - 4
Esta função tem como objetivo cortar uma `String` com mais de x caracteres e retornar uma `String`. A função recebe uma string como argumento e um número que ira servir para limite de carateres, a função ira depois verificar se a string tem ou não um número de caracteres superior ao que foi passado como parâmetro. Caso seja superior a mesma ira ser cortada e todos os caracteres depois do limite irão serão substituídos por '...' caso contrário é devolvida a string por inteiro.
```
public static String stripString(String text) {
return stripString(text, 80);
}
public static String stripString(String text, int length) {
String result = text;
if (text != null && text.length() > length) {
result = text.substring(0, length) + "...";
}
return result;
}
```
**Category-Partition**
Visto existirem dois parâmetros, a partição dos parâmetros tem de ser feita em conjunto de forma a testar todas as hipóteses possíveis para os parâmetros. O limite que deve ser estabelecido para cortar a string, deve ser testado com um número positivo, negativo e igual a 0 e a string com um número de caracteres, caso seja possível, superior, inferior e igual ao limite estabelecido.
**Limite igual a 0:**
* Limite igual a 0 e uma `String` com um número de caracteres superior a 0.
* Limite igual a 0 e uma `String` com um número de caracteres igual a 0.
Existe a hipótese de o limite ser 0, neste caso existe a possibilidade da `String` passada como argumento ter um número de carateres superior ou igual a 0.
* Limite igual a 0 e uma `String` com um número de caracteres inferior a 0.
Este cenário é impossível pois não é possível criar uma string com um número de caracteres inferior a 0.
**Limite superior a 0 (limite de 10):**
* Limite igual a 10 e uma `String` com um número de caracteres superior a 10.
* Limite igual a 10 e uma `String` com um número de caracteres inferior a 10.
* Limite igual a 10 e uma `String` com um número de caracteres igual a 10.
**Limite inferior a 0 (limite de -2):**
* Limite inferior a -2 e uma `String` com um número de caracteres igual a 10.
Para este cenário basta testar para um caso. O caso em que o limite ´inferior a 0, eliminado assim a necessidade de ter que realizar outros testes para o tamanho da `String`.
**Testes Unitários**
Para o primeiro caso da Category-Cartition, os testes para esta categoria passam por realizar 2 métodos com o limite de caracteres fixo no número 0 e em que a o único ponto de variância é o tamanho da string. Ambos os testes deram positivo, pelo que o resultado esperado é cumprido, validando assim esta categoria de testes.
O segundo caso da Category-Cartition, passa por realizar 3 métodos com o limite de caracteres igual a 10 e com uma string superior, inferior ou igual ao limite. Todos os testes deram positivo, pelo que o resultado esperado é cumprido, validando assim esta categoria de testes.
Para o caso em que o limite é negativo o tamanho da string não tem nenhuma importância, pois o *length* com um número negativo iria levantar uma exceção. Este teste levanta uma exceção pelo que deve ser prudente verificar e rever a função de forma a evitar problemas no futuro.
## Função - 5
A ultima função escolhida para realizar os testes é a função `setClipboardContent(String str)`, esta função tem como objetivo recebe uma string definir a mesma no System ClipBoard.
```
public static void setClipboardContent(String str) throws Exception {
if (str == null || str.isEmpty()) {
clearClipboardContent();
return;
}
try {
StringSelection selection = new StringSelection(str);
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, selection);
} catch (Throwable throwable) {
throw new Exception("Cannot set clipboard content.");
}
}
```
**Category-Partition**
De forma a conseguirmos testar o método na sua completude temos primeiro de analisar o parâmetro da mesma perceber quais os possíveis parâmetros. A função em questão recebe apenas uma `String` como parâmetro, o que torna os testes a realizar bastante fáceis pois só temos 3 casos possíveis.
* Parametro `String` com um valor valido. Exemplo: `"Novo conteúdo!!""`
* Parametro `String` com um valor empty. Exemplo: `""`
* Parametro `String` com um valor null. Exemplo: `null`
**Testes Unitários**
Tendo obtido quais os testes necessários a realizar, foram então criados e analisados, de modo a verificar se a função a ser avaliada se comportava como planeado.
Foram realizados 3 métodos para cobrir todas as hipóteses possíveis.
O primeiro teste foi feito com uma string válida de forma a testar se quando o parâmetro passado é valido existe algum problema. O teste foi bem-sucedido.
O segundo e terceiro testes apontam para testar se a função esta preparada para receber algo diferente de uma string válida, foram realizados testes para uma string empty e um objeto null. Ambos os testes passaram, pois, a função trato o argumento como era suposto.
Em suma, esta função passou em todos os testes que pensamos que façam sentido realizar.