From fa3c062d2decd4b67b8d6461a70451450d0cd3ef Mon Sep 17 00:00:00 2001 From: Michael Chen Date: Wed, 4 May 2022 23:56:21 +0200 Subject: [PATCH] Phase 02 Submission V1 --- .../JSONScannerTest.java | 131 ++++++++++++++++++ .../phase_02/project_phase02_tasks/Makefile | 2 +- .../Solution_Phase02_MichaelChen.tex | 49 +++++-- 3 files changed, 170 insertions(+), 12 deletions(-) create mode 100644 project_task_sheets/phase_02/project_phase02_tasks/JSONScannerTest.java diff --git a/project_task_sheets/phase_02/project_phase02_tasks/JSONScannerTest.java b/project_task_sheets/phase_02/project_phase02_tasks/JSONScannerTest.java new file mode 100644 index 0000000..872e982 --- /dev/null +++ b/project_task_sheets/phase_02/project_phase02_tasks/JSONScannerTest.java @@ -0,0 +1,131 @@ +package com.alibaba.fastjson.parser; + +import com.alibaba.fastjson.JSONException; +import org.junit.Assert; +import org.junit.Test; + + +public class JSONScannerTest { + @Test + public void inputTokenTest_Comma() throws Throwable { + JSONScanner scanner = new JSONScanner(","); + scanner.nextToken(); + Assert.assertEquals(JSONToken.COMMA, scanner.token()); + } + + @Test + public void inputTokenTest_String() throws Throwable { + JSONScanner scanner = new JSONScanner("\"text\""); + scanner.nextToken(); + Assert.assertEquals(JSONToken.LITERAL_STRING, scanner.token()); + Assert.assertEquals("text", scanner.stringVal()); + } + + @Test + public void inputTokenTest_Integer() throws Throwable { + JSONScanner scanner = new JSONScanner("-352"); + scanner.nextToken(); + Assert.assertEquals(JSONToken.LITERAL_INT, scanner.token()); + Assert.assertEquals(-352, scanner.intValue()); + } + + @Test + public void inputTokenTest_True() throws Throwable { + JSONScanner scanner = new JSONScanner("true"); + scanner.nextToken(); + Assert.assertEquals(JSONToken.TRUE, scanner.token()); + } + + @Test + public void inputTokenTest_False() throws Throwable { + JSONScanner scanner = new JSONScanner("false"); + scanner.nextToken(); + Assert.assertEquals(JSONToken.FALSE, scanner.token()); + } + + @Test + public void inputTokenTest_Float() throws Throwable { + JSONScanner scanner = new JSONScanner("2.5e2"); + scanner.nextToken(); + Assert.assertEquals(JSONToken.LITERAL_FLOAT, scanner.token()); + } + + @Test + public void inputTokenTest_Null() throws Throwable { + JSONScanner scanner = new JSONScanner("null"); + scanner.nextToken(); + Assert.assertEquals(JSONToken.NULL, scanner.token()); + } + + @Test + public void scannerSequenceTest() throws Throwable { + JSONScanner scanner = new JSONScanner("5,:"); + scanner.nextToken(); + Assert.assertEquals(JSONToken.LITERAL_INT, scanner.token()); + Assert.assertEquals(5, scanner.intValue()); + + scanner.nextToken(); + Assert.assertEquals(JSONToken.COMMA, scanner.token()); + + scanner.nextToken(); + Assert.assertEquals(JSONToken.COLON, scanner.token()); + } + + @Test + public void scannerPositionTest() throws Throwable { + JSONScanner scanner = new JSONScanner("5,:"); + scanner.nextToken(); + Assert.assertEquals(0, scanner.pos()); + + scanner.nextToken(); + Assert.assertEquals(1, scanner.pos()); + + scanner.nextToken(); + Assert.assertEquals(2, scanner.pos()); + } + + @Test + public void scannerEofTest() throws Throwable { + JSONScanner scanner = new JSONScanner("5,:"); + scanner.nextToken(); + scanner.nextToken(); + scanner.nextToken(); // colon + // scanner should now enter EOF + scanner.nextToken(); + + Assert.assertTrue(scanner.isEOF()); + Assert.assertEquals(JSONToken.EOF, scanner.token()); + } + + @Test(expected=JSONException.class) + public void scannerInputFormatTest_Invalid() throws Throwable { + JSONScanner scanner = new JSONScanner("53fds"); // invalid literal value + scanner.nextToken(); // consumes numeric token + scanner.nextToken(); // should raise invalid literal + } + + @Test() + public void complexExampleTest() throws Throwable { + JSONScanner scanner = new JSONScanner("{\"Name\":\"Michael\",\"Last\":\"Chen\"}"); + scanner.nextToken(); + Assert.assertEquals(JSONToken.LBRACE, scanner.token()); + scanner.nextToken(); + Assert.assertEquals(JSONToken.LITERAL_STRING, scanner.token()); + scanner.nextToken(); + Assert.assertEquals(JSONToken.COLON, scanner.token()); + scanner.nextToken(); + Assert.assertEquals(JSONToken.LITERAL_STRING, scanner.token()); + scanner.nextToken(); + Assert.assertEquals(JSONToken.COMMA, scanner.token()); + scanner.nextToken(); + Assert.assertEquals(JSONToken.LITERAL_STRING, scanner.token()); + scanner.nextToken(); + Assert.assertEquals(JSONToken.COLON, scanner.token()); + scanner.nextToken(); + Assert.assertEquals(JSONToken.LITERAL_STRING, scanner.token()); + scanner.nextToken(); + Assert.assertEquals(JSONToken.RBRACE, scanner.token()); + scanner.nextToken(); + Assert.assertEquals(JSONToken.EOF, scanner.token()); + } +} diff --git a/project_task_sheets/phase_02/project_phase02_tasks/Makefile b/project_task_sheets/phase_02/project_phase02_tasks/Makefile index dedf8dc..8f2f694 100644 --- a/project_task_sheets/phase_02/project_phase02_tasks/Makefile +++ b/project_task_sheets/phase_02/project_phase02_tasks/Makefile @@ -4,7 +4,7 @@ name = MichaelChen solutionname = Solution_Phase$(phase)_$(name) target = $(solutionname)_V$(version).zip -package = $(solutionname).pdf Phase02_Task2_ACTS_System.txt Phase02_Task2_ACTS_System.result.txt +package = $(solutionname).pdf Phase02_Task2_ACTS_System.txt Phase02_Task2_ACTS_System.result.txt JSONScannerTest.java latexmkflags = actspath = "C:\\Program Files (x86)\\ACTS\\acts_3.2.jar" diff --git a/project_task_sheets/phase_02/project_phase02_tasks/Solution_Phase02_MichaelChen.tex b/project_task_sheets/phase_02/project_phase02_tasks/Solution_Phase02_MichaelChen.tex index 41bb71e..7b14286 100644 --- a/project_task_sheets/phase_02/project_phase02_tasks/Solution_Phase02_MichaelChen.tex +++ b/project_task_sheets/phase_02/project_phase02_tasks/Solution_Phase02_MichaelChen.tex @@ -7,6 +7,7 @@ \usepackage{subcaption} \usepackage{amsmath} \usepackage{float} +\usepackage{fancyvrb} % for "\Verb" macro \usepackage{hyperref} \usepackage{pgf} @@ -206,12 +207,12 @@ \begin{enumerate}[topsep=0pt, leftmargin=*] \item Explain why the selected method is suitable for the input domain model approach (1-2 sentences) \begin{answer} - [TODO: Add answer here] + I chose the \texttt{JSONScanner.token()} function as a test subject. This method is particularly interesting because it is does not have any direct function parameters but rather solely depends on the state of an object as an input parameter. This does not make the method particularly suitable for the IDM approach, but it is still important to test this method extensively because the entire project is based on this. \end{answer} \item Identify the input domain of your method (2-3 sentences) \begin{answer} - [TODO: Add answer here] + The \texttt{JSONScanner} is quite a complex object and not all of the fields are of interest for this specific method so I will only name input parameters that are relevant for this test subject. Most significantly the text field of the scanner is of importance because it provides the scanner with the raw character data it has to tokenize (called $t$). Next the current token position and the token end position are important to keep track of the current state of the lexer. Finally the input text length is of importance as a boundary to the position parameters. This also influences the EOF state of the object, which signals if the input buffer is exhausted. \end{answer} \item Similar to task 2, gather the results of the following sub-tasks as shown in Table~\ref{table:example}: @@ -220,31 +221,57 @@ \item Derive sets of equivalence classes from these characteristics (Note: At least one of your partitions must consist of a number of blocks $\geq 3$. Also make sure that you have enough characteristics and corresponding blocks to derive $12$ distinct tests from them later on.) \end{enumerate} \begin{answer} - [TODO: Add answer here] + See table~\ref{tab:scannercharacteristics}. Note: the predicates valid and invalid on $t$ correspond to the input containing a well-formed sequence of tokens or not, respectively. + \begin{table} + \centering + \begin{tabular}{llll} + \hline + Characteristic & Eq-Class 1 & Eq-Class 2 & Eq-Class 3 \\ + \hline + $q_1 = \text{"input token"}$ & others & \multicolumn{2}{c}{$\forall T : \{ t = "T" \}$} \\ + $q_2 = \text{"position"}$ & $\{0<\text{pos}<\text{len}-1\}$ & $\{\text{pos}=0\}$ & $\{\text{pos}=\text{len}-1\}$ \\ + $q_3 = \text{"EOF state"}$ & $\{\text{eof} = \texttt{true}\}$ & $\{\text{eof} = \texttt{false}\}$ \\ + $q_4 = \text{"input format"}$ & $\{t\text{ is valid}\}$ & $\{t\text{ is invalid}\}$ \\ + \hline + \end{tabular} + \caption{Characteristics for the \texttt{JSONScanner.token()} function} + \label{tab:scannercharacteristics} + \end{table} \end{answer} \item Can you identify any non-valid combinations of blocks from your characteristics? (1-2 sentences) \begin{answer} - [TODO: Add answer here] + Because the EOF flag and the position are tightly coupled. If a token at the current position consumes the rest of the input buffer the object will signal an EOF soon. Another invalid combination is between characteristics $q_1$ and $q_4$, because trivially every input token as a string is also a well-formed trivial sequence of tokens, this the second class of $q_4$ is not achievable with any of the token strings. \end{answer} \item Derive (at least) one representative value for each equivalence class. Which strategy did you use for the value selection? \begin{answer} - [TODO: Add answer here] + See table~\ref{tab:scannervalues}. + \begin{table} + \centering + \begin{tabular}{llll} + \hline + Characteristic & Val-Class 1 & Val-Class 2 & Val-Class 3 \\ + \hline + $q_1 = \text{"input token"}$ & \texttt{"5,:"} & \multicolumn{2}{c}{\texttt{""text""}, \texttt{"5"}, \texttt{":"}, $\dots$} \\ + $q_2 = \text{"position"}$ & $1$ & $0$ & $\text{len}-1$ \\ + $q_3 = \text{"EOF state"}$ & \texttt{true} & \texttt{false} \\ + $q_4 = \text{"input format"}$ & \multicolumn{2}{c}{\Verb+"\{"Name":"Michael","Last":"Chen"\}"+} & \texttt{"53fds"} \\ + \hline + \end{tabular} + \caption{Characteristics for the \texttt{JSONScanner.token()} function} + \label{tab:scannervalues} + \end{table} \end{answer} \item Combine the selected values from the partitions of each input argument to complete test vectors. You can decide whether you want to approach this sub-task manually or using \textit{ACTS} (therefore, only the resulting vectors should be documented). \begin{answer} - [TODO: Add answer here] + See test suite in file \texttt{JSONScannerTest.java}. \end{answer} \item Create JUnit tests for your method, which trigger test runs with the selected test vectors, and assert each individual output. For the submission, merge all these tests into one \texttt{*.java} file. \begin{answer} - [TODO: Add answer here] - - \begin{lstlisting}[language=Java,belowskip=-0.8\baselineskip] -/* Add code here */ - \end{lstlisting} + See test suite in file \texttt{JSONScannerTest.java}. \end{answer} \end{enumerate}