void test_random_4x4() { test_initiated("a random 4x4x4 scramble"); CuboidDimensions dim = {4, 4, 4}; Algorithm * algo = algorithm_for_string("F U Uw R E' L2 Fw2 3Rw'"); Cuboid * testCuboid = algorithm_to_cuboid(algo, dim); algorithm_free(algo); if (!testCuboid) { puts("Error: failed to read cuboid."); } StickerMap * testMap = stickermap_create(dim); convert_cb_to_sm(testMap, testCuboid); cuboid_free(testCuboid); // U Uw R E' L2 Fw2 3Rw' const char * stickerData = "4662633564435556" "1441644543354332" "5226466621112113" "1111125132543222" "6424262255163316" "4655412345635533"; int i; for (i = 0; i < 16 * 6; i++) { int value = stickerData[i] - '1' + 1; if (testMap->stickers[i] != value) { printf("Error: invalid sticker at index %d, %d != %d.\n", i, value, testMap->stickers[i]); } } stickermap_free(testMap); test_completed(); }
void test_save_data_list() { test_initiated("save_data_list"); DataList * list = generate_data_list(); FILE * temp = tmpfile(); assert(temp != NULL); save_data_list(list, temp); fseek(temp, 0, SEEK_SET); DataList * loaded = load_data_list(temp); fclose(temp); if (loaded) { test_data_list_node_equality(loaded->rootNode, list->rootNode); if (loaded->dataSize != list->dataSize) { puts("Error: dataSize disagrees"); } if (loaded->headerLen != list->headerLen) { puts("Error: headerLen disagrees"); } if (loaded->depth != list->depth) { puts("Error: depth disagrees"); } } else { puts("Error: failed to load data list."); } data_list_free(loaded); data_list_free(list); test_completed(); }
void test_superflip() { test_initiated("edge orientations on superflip"); CuboidDimensions dims = {3, 3, 3}; Algorithm * algo = algorithm_for_string("(M U' M U' M U' M U' y z')3"); Cuboid * cuboid = algorithm_to_cuboid(algo, dims); algorithm_free(algo); int i; for (i = 0; i < 12; i++) { CuboidEdge edge = cuboid->edges[i]; int orX = cuboid_edge_orientation(edge, i, 0); int orY = cuboid_edge_orientation(edge, i, 0); int orZ = cuboid_edge_orientation(edge, i, 0); if (orX) { printf("Error: edge %d claims to be oriented on the X axis.\n", i); } if (orY) { printf("Error: edge %d claims to be oriented on the Y axis.\n", i); } if (orZ) { printf("Error: edge %d claims to be oriented on the Z axis.\n", i); } } cuboid_free(cuboid); test_completed(); }
void test_superflip() { test_initiated("the superflip on a 3x3x3"); CuboidDimensions dims = {3, 3, 3}; Algorithm * algo = algorithm_for_string("(M U' M U' M U' M U' y z')3"); Cuboid * cuboid = algorithm_to_cuboid(algo, dims); algorithm_free(algo); // ensure corner identity int i; for (i = 0; i < 8; i++) { CuboidCorner c = cuboid->corners[i]; if (c.index != i || c.symmetry != 0) { printf("Error: invalid corner at index %d.\n", i); } } // ensure center identity for (i = 0; i < 6; i++) { CuboidCenter c = cuboid->centers[i]; if (c.side != i + 1 || c.index != 0) { printf("Error: invalid center at index %d.\n", i); } } // ensure edge psuedo-identity for (i = 0; i < 12; i++) { CuboidEdge edge = cuboid->edges[i]; if (edge.dedgeIndex != i || edge.symmetry == 0) { printf("Error: invalid edge at index %d.\n", i); } } cuboid_free(cuboid); test_completed(); }
void test_save_cuboid() { test_initiated("save_cuboid"); CuboidDimensions dims = {10, 20, 10}; Algorithm * algo = algorithm_for_string("R2 2Bw2 3Dw L2 5Bw2 F2 4Rw2 L2 Fw2 2Uw'"); Cuboid * cuboid = algorithm_to_cuboid(algo, dims); algorithm_free(algo); FILE * temp = tmpfile(); assert(temp != NULL); save_cuboid(cuboid, temp); fseek(temp, 0, SEEK_SET); Cuboid * cb = load_cuboid(temp); fclose(temp); if (!cb) { puts("Error: failed to load cuboid at all!"); } test_cuboid_equality(cb, cuboid); cuboid_free(cb); cuboid_free(cuboid); test_completed(); }
void test_save_algorithm() { test_initiated("save_algorithm"); Algorithm * algo = algorithm_for_string("R Uw 2Fw3 D' M2 x L2 y' z2"); FILE * temp = tmpfile(); assert(temp != NULL); save_algorithm(algo, temp); fseek(temp, 0, SEEK_SET); Algorithm * loaded = load_algorithm(temp); if (!loaded) { puts("Error: failed to load algorithm at all!"); } if (loaded->type != AlgorithmTypeContainer) { puts("Error: invalid type for loaded algorithm."); } test_algorithm_equality(algo, loaded); fclose(temp); algorithm_free(algo); algorithm_free(loaded); test_completed(); }
void test_save_cuboid_search() { test_initiated("save_cuboid_search"); FILE * temp = tmpfile(); assert(temp != NULL); BSSearchState * bsState = generate_bs_search_state(); CSSearchState * state = (CSSearchState *)malloc(sizeof(CSSearchState)); state->bsState = bsState; CuboidDimensions dims = {5, 6, 6}; Algorithm * testAlgo = algorithm_for_string("Lw R2 U2 3Dw2 L'"); state->settings.rootNode = algorithm_to_cuboid(testAlgo, dims); algorithm_free(testAlgo); state->settings.algorithms = alg_list_parse("R,L,Uw2,Dw2,Fw2,Bw2", dims); save_cuboid_search(state, temp); fseek(temp, 0, SEEK_SET); CSSearchState * loaded = load_cuboid_search(temp); if (loaded) { test_cuboid_state_equality(loaded, state); cs_search_state_free(loaded); } else { puts("Error: failed to load search state."); } cs_search_state_free(state); fclose(temp); test_completed(); }
void test_generate_division() { test_initiated("sboundary_generate_division()"); SBoundary boundary; sboundary_initialize(&boundary, 5, 10); sboundary_generate_division(&boundary, 33); int digits1[] = {0, 3, 0, 3, 0}; if (memcmp(boundary.sequence, digits1, sizeof(int) * 5) != 0) { puts("Error: failed to compute 10^5 / 33."); } sboundary_generate_division(&boundary, 100000 - 1); int digits2[] = {0, 0, 0, 0, 1}; if (memcmp(boundary.sequence, digits2, sizeof(int) * 5) != 0) { puts("Error: failed to compute 10^5 / (10^5 - 1)."); } sboundary_generate_division(&boundary, 100000); if (memcmp(boundary.sequence, digits2, sizeof(int) * 5) != 0) { puts("Error: failed to compute 10^5 / 10^5."); } int digits3[] = {0, 0, 0, 0, 0}; sboundary_generate_division(&boundary, 100001); if (memcmp(boundary.sequence, digits3, sizeof(int) * 5) != 0) { puts("Error: failed to computer 10^6 / (10^6 + 1)."); } sboundary_destroy(boundary); test_completed(); }
void test_equivalent_4x4() { test_initiated("Rw equivalency on a 4x4x4."); CuboidDimensions dim = {4, 4, 4}; Algorithm * algo = algorithm_for_string("Rw2"); Cuboid * testCuboid = algorithm_to_cuboid(algo, dim); algorithm_free(algo); Cuboid * control = cuboid_half_face_turn(dim, CuboidMovesAxisX, 1); Cuboid * slice = cuboid_half_slice(dim, CuboidMovesAxisX, 1); cuboid_multiply_to(slice, control); cuboid_free(slice); // test edge equivalency int i, j; for (i = 0; i < 12; i++) { for (j = 0; j < 2; j++) { int index = j + (i * 2); CuboidEdge e1 = control->edges[index]; CuboidEdge e2 = testCuboid->edges[index]; if (e1.edgeIndex != e2.edgeIndex || e1.symmetry != e2.symmetry || e1.dedgeIndex != e2.dedgeIndex) { printf("Error: differnce in edge (%d, %d).\n", i, j); } } } // test corner equivalency for (i = 0; i < 8; i++) { CuboidCorner c1 = control->corners[i]; CuboidCorner c2 = testCuboid->corners[i]; if (c1.index != c2.index || c1.symmetry != c2.symmetry) { printf("Error: difference in corner %d.\n", i); } } // test center equivalency for (i = 1; i <= 6; i++) { for (j = 0; j < 4; j++) { int index = 4 * (i - 1) + j; CuboidCenter c1 = control->centers[index]; CuboidCenter c2 = testCuboid->centers[index]; if (c1.side != c2.side || c1.index != c2.index) { printf("Error: difference in center (%d, %d).\n", i, j); } } } cuboid_free(control); cuboid_free(testCuboid); test_completed(); }
void test_redbull_algorithm() { test_initiated("redbull on a 4x4x4"); CuboidDimensions dims = {4, 4, 4}; Algorithm * algo = algorithm_for_string("Rw2 R2 B2 U2 Lw L' U2 Rw' R U2 Rw R' U2 F2 Rw R' F2 Lw' L B2 Rw2 R2"); Cuboid * cuboid = algorithm_to_cuboid(algo, dims); algorithm_free(algo); // verify corner identity int i, j; for (i = 0; i < 8; i++) { CuboidCorner c = cuboid->corners[i]; if (c.index != i || c.symmetry != 0) { printf("Error: invalid corner at index %d.\n", i); } } // verify center identity for (i = 1; i <= 6; i++) { for (j = 0; j < 4; j++) { int index = cuboid_center_index(cuboid, i, j); CuboidCenter c = cuboid->centers[index]; if (c.side != i) { printf("Error: invalid center at (%d, %d).\n", i, j); } } } // verify edges for (i = 0; i < 12; i++) { int edgeCount = cuboid_count_edges_for_dedge(cuboid, i); for (j = 0; j < edgeCount; j++) { int index = cuboid_edge_index(cuboid, i, j); CuboidEdge edge = cuboid->edges[index]; if (i == 0) { if (edge.symmetry != 2 || edge.dedgeIndex != i || edge.edgeIndex != 1 - j) { printf("Error: invaild edge (%d, %d).\n", i, j); } } else { if (edge.symmetry != 0 || edge.dedgeIndex != i || edge.edgeIndex != j) { printf("Error: invalid edge (%d, %d).\n", i, j); } } } } cuboid_free(cuboid); test_completed(); }
void test_3x4x3_line() { test_initiated("3x4x3 \"line\" algorithm"); CuboidDimensions dims = {3, 4, 3}; const char * data = "212212212212" "121121121121" "333333333" "444444444" "666666666666" "555555555555"; StickerMap * map = stickermap_create(dims); int i; for (i = 0; i < 3*3*2 + 3*4*4; i++) { map->stickers[i] = data[i] - '1' + 1; } Cuboid * cuboid = cuboid_create(dims); if (!convert_sm_to_cb(cuboid, map)) { puts("Error: failed to read stickermap :'("); } stickermap_free(map); Algorithm * algo = algorithm_for_string("R2 L2 Uw2 R2 L2 Uw2"); Cuboid * compare = algorithm_to_cuboid(algo, dims); algorithm_free(algo); for (i = 0; i < 8; i++) { CuboidCorner c1 = compare->corners[i]; CuboidCorner c2 = cuboid->corners[i]; if (c1.index != c2.index || c1.symmetry != c2.symmetry) { printf("Error: corners differ at index %d.\n", i); printf("(expected %d, found %d)\n", c2.index, c1.index); } } for (i = 0; i < cuboid_count_edges(cuboid); i++) { CuboidEdge e1 = compare->edges[i]; CuboidEdge e2 = cuboid->edges[i]; if (e1.dedgeIndex != e2.dedgeIndex || e1.symmetry != e2.symmetry) { printf("Error: edges differ at index %d.\n", i); } } for (i = 0; i < cuboid_count_centers(cuboid); i++) { CuboidCenter c1 = compare->centers[i]; CuboidCenter c2 = cuboid->centers[i]; if (c1.side != c2.side) { printf("Error: centers differ at index %d.\n", i); } } cuboid_free(compare); cuboid_free(cuboid); test_completed(); }
void test_evil_eyes() { test_initiated("evil eyes on an 11x11x11"); CuboidDimensions dims = {11, 11, 11}; Algorithm * algo = algorithm_for_string("R2 U2 R2 U2 R2 U2"); Cuboid * evilEyes = algorithm_to_cuboid(algo, dims); algorithm_free(algo); int i, j; // verify solved centers for (i = 1; i <= 6; i++) { for (j = 0; j < 9*9; j++) { int centIndex = cuboid_center_index(evilEyes, i, j); CuboidCenter c = evilEyes->centers[centIndex]; if (c.side != i) { printf("Error: invalid center at (%d, %d).\n", i, j); } } } // verify solved corners for (i = 0; i < 8; i++) { CuboidCorner c = evilEyes->corners[i]; if (c.index != i || c.symmetry != 0) { printf("Error: invalid corner at index %d.\n", i); } } for (i = 0; i < 12; i++) { int expectedDedge = i; if (i == 0) expectedDedge = 6; if (i == 6) expectedDedge = 0; if (i == 1) expectedDedge = 7; if (i == 7) expectedDedge = 1; int dedgeCount = cuboid_count_edges_for_dedge(evilEyes, i); for (j = 0; j < dedgeCount; j++) { int index = cuboid_edge_index(evilEyes, i, j); CuboidEdge edge = evilEyes->edges[index]; if (edge.symmetry != 0 || edge.dedgeIndex != expectedDedge) { printf("Error: invalid edge at (%d, %d).\n", i, j); } } } cuboid_free(evilEyes); test_completed(); }
void test_rl_orientation() { test_initiated("R & L edge orientation"); CuboidDimensions dims = {3, 3, 3}; Algorithm * algo = algorithm_for_string("R U2 D' F' U2 L' B2 D' F"); Cuboid * cuboid = algorithm_to_cuboid(algo, dims); uint8_t eoMap[12] = {0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0}; int i; for (i = 0; i < 12; i++) { CuboidEdge edge = cuboid->edges[i]; uint8_t flag = cuboid_edge_orientation(edge, i, 0); if (flag != eoMap[i]) { printf("Error: invalid EO at %d.\n", i); } } cuboid_free(cuboid); test_completed(); }
void test_fb_orientation() { test_initiated("F & B edge orientation"); CuboidDimensions dims = {3, 3, 3}; Algorithm * algo = algorithm_for_string("R D2 F L' U2 D' F2 L' B"); Cuboid * cuboid = algorithm_to_cuboid(algo, dims); uint8_t eoMap[12] = {1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1}; // I entered this SO fast int i; for (i = 0; i < 12; i++) { CuboidEdge edge = cuboid->edges[i]; uint8_t flag = cuboid_edge_orientation(edge, i, 2); if (flag != eoMap[i]) { printf("Error: invalid EO at %d.\n", i); } } cuboid_free(cuboid); test_completed(); }
void test_5x5x5_turns() { test_initiated("5x5x5 half-turns"); CuboidDimensions dims = {5, 5, 5}; Cuboid * turnR = cuboid_half_face_turn(dims, CuboidMovesAxisX, 1); uint8_t rightCenter[] = {8, 7, 6, 5, 4, 3, 2, 1, 0}; int i; for (i = 0; i < 9; i++) { CuboidCenter c = turnR->centers[cuboid_center_index(turnR, 5, i)]; if (c.index != rightCenter[i]) { printf("Error: invalid right center at index %d.\n", i); } int j; for (j = 1; j <= 6; j++) { if (j == 5) continue; CuboidCenter cent = turnR->centers[cuboid_center_index(turnR, j, i)]; if (cent.index != i || cent.side != j) { printf("Error: invalid center piece (%d, %d).\n", j, i); } } } // check the right dedges uint8_t checkEdges[4] = {1, 5, 7, 11}; for (i = 0; i < 4; i++) { int j, dedgeIndex = checkEdges[i]; int complementDedge = (i < 2 ? checkEdges[i + 2] : checkEdges[i - 2]); for (j = 0; j < 3; j++) { CuboidEdge edge = turnR->edges[cuboid_edge_index(turnR, dedgeIndex, j)]; if (edge.edgeIndex != 3 - j - 1 || edge.dedgeIndex != complementDedge) { printf("Error: invalid edge at (%d, %d), got (%d, %d).\n", dedgeIndex, j, edge.dedgeIndex, edge.dedgeIndex); } } } cuboid_free(turnR); test_completed(); }
void test_save_base_search() { test_initiated("save_base_search"); BSSearchState * state = generate_bs_search_state(); FILE * temp = tmpfile(); assert(temp != NULL); save_base_search(state, temp); fseek(temp, 0, SEEK_SET); BSSearchState * loaded = load_base_search(temp); if (loaded) { test_base_state_equality(state, loaded); bs_search_state_free(loaded); } else { puts("Error: failed to load!"); } fclose(temp); bs_search_state_free(state); test_completed(); }
void test_maximum_minimum() { test_initiated("srange_minimum/maximum_digit()"); SBoundary lower, upper; sboundary_initialize(&lower, 9, 12); sboundary_initialize(&upper, 9, 12); int lowerData[9] = {4, 5, 8, 6, 10, 9, 0, 0, 0}; int upperData[9] = {10, 7, 2, 1, 3, 4, 7, 0, 0}; memcpy(lower.sequence, lowerData, 9 * sizeof(int)); memcpy(upper.sequence, upperData, 9 * sizeof(int)); SRange range = {lower, upper}; int test = srange_minimum_digit(range, 3, int_list("\x04\x05\x08")); if (test != 6) { puts("Error: minimum 3 digits failed."); } test = srange_minimum_digit(range, 4, int_list("\x05\x00\x00\x00")); if (test != 0) { puts("Error: going above minimum failed."); } test = srange_maximum_digit(range, 2, int_list("\x10\x07")); if (test != 2) { puts("Error: maximum 2 digits failed."); } test = srange_maximum_digit(range, 6, int_list("\x10\x07\x02\x01\x03\x04")); if (test != 6) { puts("Error: maximum value blocking failed."); } test = srange_maximum_digit(range, 7, int_list("\x10\x07\x02\x01\x03\x04\x06")); if (test != 11) { puts("Error: going below maximum failed."); } sboundary_destroy(lower); sboundary_destroy(upper); test_completed(); }
void test_random_3x3() { test_initiated("a random 3x3x3 scramble"); CuboidDimensions dim = {3, 3, 3}; Algorithm * algo = algorithm_for_string("D L2 D2 R2 B2 D' F2 R' F2 L' R' U' R2 U2 L2 U2 B D' U2 L' D2 B U'"); Cuboid * testCuboid = algorithm_to_cuboid(algo, dim); algorithm_free(algo); StickerMap * testMap = stickermap_create(dim); convert_cb_to_sm(testMap, testCuboid); cuboid_free(testCuboid); // scrambled with D L2 D2 R2 B2 D' F2 R' F2 L' R' U' R2 U2 L2 U2 B D' U2 L' D2 B U' (23 HTM) const char * stickerData = "321312451" "166126216" "445436546" "524542453" "313653536" "212365142"; int i; for (i = 0; i < 9 * 6; i++) { int value = stickerData[i] - '1' + 1; if (testMap->stickers[i] != value) { printf("Error: invalid sticker at index %d, %d != %d.\n", i, value, testMap->stickers[i]); } } stickermap_free(testMap); test_completed(); }
void test_range_division() { test_initiated("Testing srange_division()"); SRange * ranges = (SRange *)malloc(sizeof(SRange) * 50); int count = srange_division(2, 5, 50, ranges); if (count != 25) { puts("Error: dividing 25 into 50 pieces should yield 25 pieces!"); } srange_destroy_list(ranges, count); count = srange_division(2, 10, 50, ranges); if (count != 50) { puts("Error: dividing 100 by 50 should yield 50 pieces!"); } SRange r1 = ranges[0]; if (!sboundary_is_zero(r1.lower)) { puts("Error: first boundary should be zero."); } if (r1.upper.sequence[0] != 0 || r1.upper.sequence[1] != 2) { puts("Error: second boundary should be (0, 2)."); } r1 = ranges[count - 1]; if (r1.lower.sequence[0] != 9 || r1.lower.sequence[1] != 8) { puts("Error: invalid second to last boundary."); } if (r1.upper.sequence[0] != 10 || r1.upper.sequence[1] != 0) { puts("Error: invalid last boundary."); } srange_destroy_list(ranges, count); free(ranges); test_completed(); }
/* * Callback upon request completion. */ static void on_request_complete(pj_stun_session *stun_sess, pj_status_t status, void *token, pj_stun_tx_data *tdata, const pj_stun_msg *response, const pj_sockaddr_t *src_addr, unsigned src_addr_len) { nat_detect_session *sess; pj_stun_sockaddr_attr *mattr = NULL; pj_stun_changed_addr_attr *ca = NULL; pj_uint32_t *tsx_id; int cmp; unsigned test_id; PJ_UNUSED_ARG(token); PJ_UNUSED_ARG(tdata); PJ_UNUSED_ARG(src_addr); PJ_UNUSED_ARG(src_addr_len); sess = (nat_detect_session*) pj_stun_session_get_user_data(stun_sess); pj_grp_lock_acquire(sess->grp_lock); /* Find errors in the response */ if (status == PJ_SUCCESS) { /* Check error message */ if (PJ_STUN_IS_ERROR_RESPONSE(response->hdr.type)) { pj_stun_errcode_attr *eattr; int err_code; eattr = (pj_stun_errcode_attr*) pj_stun_msg_find_attr(response, PJ_STUN_ATTR_ERROR_CODE, 0); if (eattr != NULL) err_code = eattr->err_code; else err_code = PJ_STUN_SC_SERVER_ERROR; status = PJ_STATUS_FROM_STUN_CODE(err_code); } else { /* Get MAPPED-ADDRESS or XOR-MAPPED-ADDRESS */ mattr = (pj_stun_sockaddr_attr*) pj_stun_msg_find_attr(response, PJ_STUN_ATTR_XOR_MAPPED_ADDR, 0); if (mattr == NULL) { mattr = (pj_stun_sockaddr_attr*) pj_stun_msg_find_attr(response, PJ_STUN_ATTR_MAPPED_ADDR, 0); } if (mattr == NULL) { status = PJNATH_ESTUNNOMAPPEDADDR; } /* Get CHANGED-ADDRESS attribute */ ca = (pj_stun_changed_addr_attr*) pj_stun_msg_find_attr(response, PJ_STUN_ATTR_CHANGED_ADDR, 0); if (ca == NULL) { status = PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_SERVER_ERROR); } } } /* Save the result */ tsx_id = (pj_uint32_t*) tdata->msg->hdr.tsx_id; test_id = tsx_id[2]; if (test_id >= ST_MAX) { PJ_LOG(4,(sess->pool->obj_name, "Invalid transaction ID %u in response", test_id)); end_session(sess, PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_SERVER_ERROR), PJ_STUN_NAT_TYPE_ERR_UNKNOWN); goto on_return; } PJ_LOG(5,(sess->pool->obj_name, "Completed %s, status=%d", test_names[test_id], status)); sess->result[test_id].complete = PJ_TRUE; sess->result[test_id].status = status; if (status == PJ_SUCCESS) { pj_memcpy(&sess->result[test_id].ma, &mattr->sockaddr.ipv4, sizeof(pj_sockaddr_in)); pj_memcpy(&sess->result[test_id].ca, &ca->sockaddr.ipv4, sizeof(pj_sockaddr_in)); } /* Send Test 1B only when Test 2 completes. Must not send Test 1B * before Test 2 completes to avoid creating mapping on the NAT. */ if (!sess->result[ST_TEST_1B].executed && sess->result[ST_TEST_2].complete && sess->result[ST_TEST_2].status != PJ_SUCCESS && sess->result[ST_TEST_1].complete && sess->result[ST_TEST_1].status == PJ_SUCCESS) { cmp = pj_memcmp(&sess->local_addr, &sess->result[ST_TEST_1].ma, sizeof(pj_sockaddr_in)); if (cmp != 0) send_test(sess, ST_TEST_1B, &sess->result[ST_TEST_1].ca, 0); } if (test_completed(sess)<3 || test_completed(sess)!=test_executed(sess)) goto on_return; /* Handle the test result according to RFC 3489 page 22: +--------+ | Test | | 1 | +--------+ | | V /\ /\ N / \ Y / \ Y +--------+ UDP <-------/Resp\--------->/ IP \------------->| Test | Blocked \ ? / \Same/ | 2 | \ / \? / +--------+ \/ \/ | | N | | V V /\ +--------+ Sym. N / \ | Test | UDP <---/Resp\ | 2 | Firewall \ ? / +--------+ \ / | \/ V |Y /\ /\ | Symmetric N / \ +--------+ N / \ V NAT <--- / IP \<-----| Test |<--- /Resp\ Open \Same/ | 1B | \ ? / Internet \? / +--------+ \ / \/ \/ | |Y | | | V | Full | Cone V /\ +--------+ / \ Y | Test |------>/Resp\---->Restricted | 3 | \ ? / +--------+ \ / \/ |N | Port +------>Restricted Figure 2: Flow for type discovery process */ switch (sess->result[ST_TEST_1].status) { case PJNATH_ESTUNTIMEDOUT: /* * Test 1 has timed-out. Conclude with NAT_TYPE_BLOCKED. */ end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_BLOCKED); break; case PJ_SUCCESS: /* * Test 1 is successful. Further tests are needed to detect * NAT type. Compare the MAPPED-ADDRESS with the local address. */ cmp = pj_memcmp(&sess->local_addr, &sess->result[ST_TEST_1].ma, sizeof(pj_sockaddr_in)); if (cmp==0) { /* * MAPPED-ADDRESS and local address is equal. Need one more * test to determine NAT type. */ switch (sess->result[ST_TEST_2].status) { case PJ_SUCCESS: /* * Test 2 is also successful. We're in the open. */ end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_OPEN); break; case PJNATH_ESTUNTIMEDOUT: /* * Test 2 has timed out. We're behind somekind of UDP * firewall. */ end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_SYMMETRIC_UDP); break; default: /* * We've got other error with Test 2. */ end_session(sess, sess->result[ST_TEST_2].status, PJ_STUN_NAT_TYPE_ERR_UNKNOWN); break; } } else { /* * MAPPED-ADDRESS is different than local address. * We're behind NAT. */ switch (sess->result[ST_TEST_2].status) { case PJ_SUCCESS: /* * Test 2 is successful. We're behind a full-cone NAT. */ end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_FULL_CONE); break; case PJNATH_ESTUNTIMEDOUT: /* * Test 2 has timed-out Check result of test 1B.. */ switch (sess->result[ST_TEST_1B].status) { case PJ_SUCCESS: /* * Compare the MAPPED-ADDRESS of test 1B with the * MAPPED-ADDRESS returned in test 1.. */ cmp = pj_memcmp(&sess->result[ST_TEST_1].ma, &sess->result[ST_TEST_1B].ma, sizeof(pj_sockaddr_in)); if (cmp != 0) { /* * MAPPED-ADDRESS is different, we're behind a * symmetric NAT. */ end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_SYMMETRIC); } else { /* * MAPPED-ADDRESS is equal. We're behind a restricted * or port-restricted NAT, depending on the result of * test 3. */ switch (sess->result[ST_TEST_3].status) { case PJ_SUCCESS: /* * Test 3 is successful, we're behind a restricted * NAT. */ end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_RESTRICTED); break; case PJNATH_ESTUNTIMEDOUT: /* * Test 3 failed, we're behind a port restricted * NAT. */ end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_PORT_RESTRICTED); break; default: /* * Got other error with test 3. */ end_session(sess, sess->result[ST_TEST_3].status, PJ_STUN_NAT_TYPE_ERR_UNKNOWN); break; } } break; case PJNATH_ESTUNTIMEDOUT: /* * Strangely test 1B has failed. Maybe connectivity was * lost? Or perhaps port 3489 (the usual port number in * CHANGED-ADDRESS) is blocked? */ switch (sess->result[ST_TEST_3].status) { case PJ_SUCCESS: /* Although test 1B failed, test 3 was successful. * It could be that port 3489 is blocked, while the * NAT itself looks to be a Restricted one. */ end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_RESTRICTED); break; default: /* Can't distinguish between Symmetric and Port * Restricted, so set the type to Unknown */ end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_ERR_UNKNOWN); break; } break; default: /* * Got other error with test 1B. */ end_session(sess, sess->result[ST_TEST_1B].status, PJ_STUN_NAT_TYPE_ERR_UNKNOWN); break; } break; default: /* * We've got other error with Test 2. */ end_session(sess, sess->result[ST_TEST_2].status, PJ_STUN_NAT_TYPE_ERR_UNKNOWN); break; } } break; default: /* * We've got other error with Test 1. */ end_session(sess, sess->result[ST_TEST_1].status, PJ_STUN_NAT_TYPE_ERR_UNKNOWN); break; } on_return: pj_grp_lock_release(sess->grp_lock); }
void test_3x2x3_turns() { test_initiated("3x2x3 half-turns"); CuboidDimensions dims = {3, 2, 3}; Cuboid * turnR = cuboid_half_face_turn(dims, CuboidMovesAxisX, 1); Cuboid * turnU = cuboid_half_face_turn(dims, CuboidMovesAxisY, 1); // validate R turn edges CuboidEdge edge1 = turnR->edges[cuboid_edge_index(turnR, 5, 0)]; CuboidEdge edge2 = turnR->edges[cuboid_edge_index(turnR, 11, 0)]; if (edge1.symmetry != 0 || edge1.dedgeIndex != 11) { puts("Error: dedge 5 is incorrect.\n"); } if (edge2.symmetry != 0 || edge2.dedgeIndex != 5) { puts("Error: dedge 11 is incorrect.\n"); } int i; for (i = 0; i < 12; i++) { if (i == 5 || i == 11) continue; if (cuboid_count_edges_for_dedge(turnR, i) != 1) { if (i == 1 || i == 3 || i == 7 || i == 9) continue; printf("Error: representation does not see edge at %d\n", i); continue; } CuboidEdge edge = turnR->edges[cuboid_edge_index(turnR, i, 0)]; if (edge.dedgeIndex != i) { printf("Error: edge at %d is incorrect.\n", i); } } // validate R turn corners uint8_t expectedCorners[8] = {0, 1, 2, 3, 7, 6, 5, 4}; for (i = 0; i < 8; i++) { if (turnR->corners[i].index != expectedCorners[i]) { printf("Error: wrong corner at index %d, got %d.\n", i, turnR->corners[i].index); } } // perform evil eyes and ensure proper swap Cuboid * cuboid = cuboid_create(dims); for (i = 0; i < 3; i++) { cuboid_multiply_to(turnR, cuboid); cuboid_multiply_to(turnU, cuboid); } edge1 = cuboid->edges[cuboid_edge_index(cuboid, 0, 0)]; edge2 = cuboid->edges[cuboid_edge_index(cuboid, 6, 0)]; if (edge1.dedgeIndex != 6) { printf("Error: invalid evil eyes dedge at index 0, actual is %d\n", edge1.dedgeIndex); } if (edge2.dedgeIndex != 0) { puts("Error: invalid evil eyes dedge at index 6"); } for (i = 0; i < 12; i++) { if (i == 6 || i == 0) continue; if (cuboid_count_edges_for_dedge(turnR, i) != 1) continue; CuboidEdge edge = cuboid->edges[cuboid_edge_index(cuboid, i, 0)]; if (edge.dedgeIndex != i) { printf("Error: wrong edge at index %d.\n", i); } } cuboid_free(cuboid); cuboid_free(turnR); cuboid_free(turnU); test_completed(); }
void test_3x4x3_slices() { test_initiated("3x4x3 double slices"); CuboidDimensions dims = {3, 4, 3}; Cuboid * htSlice = cuboid_half_slice(dims, CuboidMovesAxisY, 0); uint8_t dedges[4] = {1, 3, 7, 9}; uint8_t newEdges[4] = {9, 7, 3, 1}; // verify edges of HT int i, j; for (i = 0; i < 4; i++) { CuboidEdge edge = htSlice->edges[cuboid_edge_index(htSlice, dedges[i], 0)]; if (edge.dedgeIndex != newEdges[i] || edge.edgeIndex != 0) { printf("Error: invalid dedge %d.\n", dedges[i]); } } for (i = 0; i < 12; i++) { int edgeCount = cuboid_count_edges_for_dedge(htSlice, i); for (j = 0; j < edgeCount; j++) { if (i == 1 || i == 3 || i == 7 || i == 9) { if (j == 0) continue; } CuboidEdge edge = htSlice->edges[cuboid_edge_index(htSlice, i, j)]; if (edge.edgeIndex != j || edge.dedgeIndex != i) { printf("Error: invalid edge (%d, %d).\n", i, j); } } } // verify centers of HT uint8_t centers[4] = {1, 2, 5, 6}; uint8_t newCenters[4] = {2, 1, 6, 5}; for (i = 0; i < 4; i++) { CuboidCenter c = htSlice->centers[cuboid_center_index(htSlice, centers[i], 0)]; if (c.index != 0 || c.side != newCenters[i]) { printf("Error: invalid center on face %d.\n", centers[i]); } } for (i = 1; i <= 6; i++) { int centCount = cuboid_count_centers_for_face(htSlice, i); for (j = 0; j < centCount; j++) { if (i != 3 && i != 4) { if (j == 0) continue; } CuboidCenter c = htSlice->centers[cuboid_center_index(htSlice, i, j)]; if (c.index != j || c.side != i) { printf("Error: invalid center at (%d, %d).\n", i, j); } } } Cuboid * shouldEqual = cuboid_create(dims); Cuboid * qtSlice = cuboid_quarter_slice(dims, CuboidMovesAxisY, 0); cuboid_multiply_to(qtSlice, shouldEqual); cuboid_multiply_to(qtSlice, shouldEqual); cuboid_free(qtSlice); // ensure that shouldEqual = htSlice for (i = 0; i < cuboid_count_centers(htSlice); i++) { CuboidCenter c1 = htSlice->centers[i]; CuboidCenter c2 = shouldEqual->centers[i]; if (c1.index != c2.index || c1.side != c2.side) { printf("Error: different center at index %d.\n", i); } } for (i = 0; i < cuboid_count_edges(htSlice); i++) { CuboidEdge e1 = htSlice->edges[i]; CuboidEdge e2 = shouldEqual->edges[i]; if (e1.dedgeIndex != e2.dedgeIndex || e1.edgeIndex != e2.edgeIndex || e1.symmetry != e2.symmetry) { printf("Error: different edges at index %d.\n", i); } } cuboid_free(shouldEqual); cuboid_free(htSlice); test_completed(); }
void test_tokens() { test_initiated("individual tokens"); // test Rw Algorithm * wideRight = algorithm_for_token("Rw"); if (wideRight->type != AlgorithmTypeWideTurn) puts("Error: Rw processed invalid type."); if (wideRight->contents.wideTurn.face != 'R') puts("Error: Rw processed invalid face."); if (wideRight->contents.wideTurn.numLayers != 2) puts("Error: Rw processed invalid layer count."); if (wideRight->inverseFlag) puts("Error: Rw processed an inverse."); if (wideRight->power != 1) puts("Error: Rw processed the wrong power."); algorithm_free(wideRight); Algorithm * shouldBeNull = algorithm_for_token("2M"); if (shouldBeNull != NULL) { puts("Error: failed to detect that 2M is invalid."); algorithm_free(shouldBeNull); } Algorithm * mPrime = algorithm_for_token("M'"); if (mPrime->type != AlgorithmTypeSlice) puts("Error: M' processed invalid type."); if (mPrime->contents.slice.layer != 'M') puts("Error: M' processed invalid slice."); if (!mPrime->inverseFlag) puts("Error: M' did not process the inverse."); if (mPrime->power != 1) puts("Error: M' processed the wrong power."); algorithm_free(mPrime); // test 3Uw2 Algorithm * upWide = algorithm_for_token("13Uw2"); if (upWide->type != AlgorithmTypeWideTurn) puts("Error: 13Uw2 processed invalid type."); if (upWide->contents.wideTurn.face != 'U') puts("Error: 13Uw2 processed invalid face."); if (upWide->contents.wideTurn.numLayers != 13) puts("Error: 13Uw2 processed invalid layer count."); if (upWide->inverseFlag) puts("Error: 13Uw2 processed an inverse."); if (upWide->power != 2) puts("Error: 13Uw2 processed the wrong power."); algorithm_free(upWide); Algorithm * rotation = algorithm_for_token("x'3"); if (rotation->type != AlgorithmTypeRotation) puts("Error: x'3 processed invalid type."); if (rotation->contents.rotation.axis != 'x') puts("Error: x'3 processed invalid axis."); if (!rotation->inverseFlag) puts("Error: x'3 processed invalid inverse flag."); if (rotation->power != 3) puts("Error: x'3 processed invalid power."); algorithm_free(rotation); test_completed(); }
void test_algorithm() { test_initiated("algorithm parser"); Algorithm * algo = algorithm_for_string("R2 U' 12Rw15 (R z2)2 R' S'"); if (algorithm_container_count(algo) != 6) { puts("Error: invalid algorithm token count."); } Algorithm * algo1 = algorithm_container_get(algo, 0); if (algo1->type != AlgorithmTypeWideTurn || algo1->contents.wideTurn.face != 'R' || algo1->contents.wideTurn.numLayers != 1 || algo1->inverseFlag != 0 || algo1->power != 2) { puts("Error: invalid token at index 0."); } algo1 = algorithm_container_get(algo, 1); if (algo1->type != AlgorithmTypeWideTurn || algo1->contents.wideTurn.face != 'U' || algo1->contents.wideTurn.numLayers != 1 || algo1->inverseFlag != 1 || algo1->power != 1) { puts("Error: invalid token at index 1."); } algo1 = algorithm_container_get(algo, 2); if (algo1->type != AlgorithmTypeWideTurn || algo1->contents.wideTurn.face != 'R' || algo1->contents.wideTurn.numLayers != 12 || algo1->inverseFlag != 0 || algo1->power != 15) { puts("Error: invalid token at index 2."); } algo1 = algorithm_container_get(algo, 4); if (algo1->type != AlgorithmTypeWideTurn || algo1->contents.wideTurn.face != 'R' || algo1->contents.wideTurn.numLayers != 1 || algo1->inverseFlag != 1 || algo1->power != 1) { puts("Error: invalid token at index 4."); } algo1 = algorithm_container_get(algo, 5); if (algo1->type != AlgorithmTypeSlice || algo1->contents.slice.layer != 'S' || algo1->inverseFlag != 1 || algo1->power != 1) { puts("Error: invalid token at index 5."); } Algorithm * nested = algorithm_container_get(algo, 3); if (nested->type != AlgorithmTypeContainer) { puts("Error: invalid type for nested subexpression at index 3."); } if (algorithm_container_count(nested) != 2) { puts("Error: invalid count for nested subexpression."); } if (nested->power != 2) { puts("Error: invalid power on nested subexpression."); } algo1 = algorithm_container_get(nested, 0); if (algo1->type != AlgorithmTypeWideTurn || algo1->contents.wideTurn.face != 'R' || algo1->contents.wideTurn.numLayers != 1 || algo1->inverseFlag != 0 || algo1->power != 1) { puts("Error: invalid token at subexpression index 0."); } algo1 = algorithm_container_get(nested, 1); if (algo1->type != AlgorithmTypeRotation || algo1->contents.rotation.axis != 'z' || algo1->inverseFlag != 0 || algo1->power != 2) { puts("Error: invalid token at subexpression index 1."); } algorithm_free(algo); test_completed(); }